diff --git a/CHANGELOG.md b/CHANGELOG.md index 45e54de0830b..c403badef818 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -21,6 +21,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Do not emit `@keyframes` in `@theme reference` ([#16120](https://github.com/tailwindlabs/tailwindcss/pull/16120)) - Discard invalid declarations when parsing CSS ([#16093](https://github.com/tailwindlabs/tailwindcss/pull/16093)) - Do not emit empty CSS rules and at-rules ([#16121](https://github.com/tailwindlabs/tailwindcss/pull/16121)) +- Handle `@variant` when at the top-level of a stylesheet ([#16129](https://github.com/tailwindlabs/tailwindcss/pull/16129)) ## [4.0.1] - 2025-01-29 diff --git a/packages/tailwindcss/src/index.test.ts b/packages/tailwindcss/src/index.test.ts index ec4671e97268..67a0a3d64dab 100644 --- a/packages/tailwindcss/src/index.test.ts +++ b/packages/tailwindcss/src/index.test.ts @@ -3510,6 +3510,38 @@ describe('@variant', () => { background: white; } } + + @variant hover { + @variant landscape { + .btn2 { + color: red; + } + } + } + + @variant hover { + .foo { + color: red; + } + @variant landscape { + .bar { + color: blue; + } + } + .baz { + @variant portrait { + color: green; + } + } + } + + @media something { + @variant landscape { + @page { + color: red; + } + } + } `, [], ), @@ -3522,6 +3554,38 @@ describe('@variant', () => { .btn { background: #fff; } + } + + @media (hover: hover) { + @media (orientation: landscape) { + :scope:hover .btn2 { + color: red; + } + } + + :scope:hover .foo { + color: red; + } + + @media (orientation: landscape) { + :scope:hover .bar { + color: #00f; + } + } + + @media (orientation: portrait) { + :scope:hover .baz { + color: green; + } + } + } + + @media something { + @media (orientation: landscape) { + @page { + color: red; + } + } }" `) }) diff --git a/packages/tailwindcss/src/index.ts b/packages/tailwindcss/src/index.ts index d594397ede6e..2baed9acf6a5 100644 --- a/packages/tailwindcss/src/index.ts +++ b/packages/tailwindcss/src/index.ts @@ -244,6 +244,11 @@ async function parseCss( return WalkAction.Stop } }) + + // No `@slot` found, so this is still a regular `@variant` at-rule + if (node.name === '@variant') { + variantNodes.push(node) + } } } @@ -429,6 +434,13 @@ async function parseCss( replaceWith(node.nodes) } + walk(node.nodes, (node) => { + if (node.kind !== 'at-rule') return + if (node.name !== '@variant') return + + variantNodes.push(node) + }) + return WalkAction.Skip }