Skip to content

Commit 66ef77c

Browse files
Emit @keyframes in prefixed setup (#16850)
Closes #16829 We were only adding keyframes used in variables starting with `--animate` (without adding a potential prefix). ## Test plan - Added a unit test
1 parent 5532d48 commit 66ef77c

File tree

4 files changed

+72
-4
lines changed

4 files changed

+72
-4
lines changed

CHANGELOG.md

+1
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
1818
### Fixed
1919

2020
- Ensure `not-*` does not remove `:is(…)` from variants ([#16825](https://github.com/tailwindlabs/tailwindcss/pull/16825))
21+
- Ensure `@keyframes` are correctly emitted when using a prefixed setup ([#16850](https://github.com/tailwindlabs/tailwindcss/pull/16850))
2122

2223
## [4.0.9] - 2025-02-25
2324

packages/tailwindcss/src/ast.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -429,7 +429,7 @@ export function optimizeAst(ast: AstNode[], designSystem: DesignSystem) {
429429
variableDependencies,
430430
)
431431
if (variableUsed) {
432-
if (declaration.property.startsWith('--animate-')) {
432+
if (declaration.property.startsWith(designSystem.theme.prefixKey('--animate-'))) {
433433
let parts = declaration.value!.split(/\s+/)
434434
for (let part of parts) usedKeyframeNames.add(part)
435435
}

packages/tailwindcss/src/index.test.ts

+67
Original file line numberDiff line numberDiff line change
@@ -1613,6 +1613,73 @@ describe('Parsing theme values from CSS', () => {
16131613
`)
16141614
})
16151615

1616+
test('keyframes are generated when used in an animation within a prefixed setup', async () => {
1617+
expect(
1618+
await compileCss(
1619+
css`
1620+
@theme prefix(tw) {
1621+
--animate-foo: used 1s infinite;
1622+
--animate-bar: unused 1s infinite;
1623+
1624+
@keyframes used {
1625+
to {
1626+
opacity: 1;
1627+
}
1628+
}
1629+
1630+
@keyframes unused {
1631+
to {
1632+
opacity: 0;
1633+
}
1634+
}
1635+
}
1636+
1637+
@tailwind utilities;
1638+
`,
1639+
['tw:animate-foo'],
1640+
),
1641+
).toMatchInlineSnapshot(`
1642+
":root, :host {
1643+
--tw-animate-foo: used 1s infinite;
1644+
}
1645+
1646+
.tw\\:animate-foo {
1647+
animation: var(--tw-animate-foo);
1648+
}
1649+
1650+
@keyframes used {
1651+
to {
1652+
opacity: 1;
1653+
}
1654+
}"
1655+
`)
1656+
})
1657+
1658+
test('custom properties are generated when used from a CSS var with a prefixed setup', async () => {
1659+
expect(
1660+
await compileCss(
1661+
css`
1662+
@theme prefix(tw) {
1663+
--color-tomato: #e10c04;
1664+
}
1665+
@tailwind utilities;
1666+
.red {
1667+
color: var(--tw-color-tomato);
1668+
}
1669+
`,
1670+
[],
1671+
),
1672+
).toMatchInlineSnapshot(`
1673+
":root, :host {
1674+
--tw-color-tomato: #e10c04;
1675+
}
1676+
1677+
.red {
1678+
color: var(--tw-color-tomato);
1679+
}"
1680+
`)
1681+
})
1682+
16161683
// https://github.com/tailwindlabs/tailwindcss/issues/16374
16171684
test('custom properties in keyframes preserved', async () => {
16181685
expect(

packages/tailwindcss/src/theme.ts

+3-3
Original file line numberDiff line numberDiff line change
@@ -117,12 +117,12 @@ export class Theme {
117117
if (!this.prefix) return this.values.entries()
118118

119119
return Array.from(this.values, (entry) => {
120-
entry[0] = this.#prefixKey(entry[0])
120+
entry[0] = this.prefixKey(entry[0])
121121
return entry
122122
})
123123
}
124124

125-
#prefixKey(key: string) {
125+
prefixKey(key: string) {
126126
if (!this.prefix) return key
127127
return `--${this.prefix}-${key.slice(2)}`
128128
}
@@ -190,7 +190,7 @@ export class Theme {
190190
fallback = value.value
191191
}
192192

193-
return `var(${escape(this.#prefixKey(themeKey))}${fallback ? `, ${fallback}` : ''})`
193+
return `var(${escape(this.prefixKey(themeKey))}${fallback ? `, ${fallback}` : ''})`
194194
}
195195

196196
markUsedVariable(themeKey: string) {

0 commit comments

Comments
 (0)