Skip to content

Commit 3ab7f12

Browse files
Fix container names with hyphens (#17628)
Fixes #17614. Candidate parsing for variants only account for the root `@` if there no hyphens. It seems like the current logic assumes if it *does* have a hyphen, then it would be one of `@min` or `@max`. However, with: ```css @theme { --container-foo-bar: 1440px; } ``` Then `@foo-bar` should be valid. However, we only check for `@foo-bar` and `@foo` as roots, but never `@`. This PR adds a check for `@` at the very end after iterating through root permutations. --------- Co-authored-by: Philipp Spiess <[email protected]>
1 parent cdecb55 commit 3ab7f12

File tree

4 files changed

+83
-11
lines changed

4 files changed

+83
-11
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
1212
- Ensure `color-mix(…)` polyfills do not cause used CSS variables to be removed ([#17555](https://github.com/tailwindlabs/tailwindcss/pull/17555))
1313
- Ensure the `color-mix(…)` polyfill creates fallbacks for theme variables that reference other theme variables ([#17562](https://github.com/tailwindlabs/tailwindcss/pull/17562))
1414
- Fix brace expansion in `@source inline('z-{10..0}')` with range going down ([#17591](https://github.com/tailwindlabs/tailwindcss/pull/17591))
15+
- Ensure container query variant names can contain hyphens ([#17628](https://github.com/tailwindlabs/tailwindcss/pull/17628))
1516

1617
## [4.1.3] - 2025-04-04
1718

packages/tailwindcss/src/candidate.test.ts

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1294,6 +1294,36 @@ it('should parse a functional variant starting with @', () => {
12941294
`)
12951295
})
12961296

1297+
it('should parse a functional variant starting with @ that has a hyphen', () => {
1298+
let utilities = new Utilities()
1299+
utilities.static('flex', () => [])
1300+
1301+
let variants = new Variants()
1302+
variants.functional('@', () => {})
1303+
1304+
expect(run('@foo-bar:flex', { utilities, variants })).toMatchInlineSnapshot(`
1305+
[
1306+
{
1307+
"important": false,
1308+
"kind": "static",
1309+
"raw": "@foo-bar:flex",
1310+
"root": "flex",
1311+
"variants": [
1312+
{
1313+
"kind": "functional",
1314+
"modifier": null,
1315+
"root": "@",
1316+
"value": {
1317+
"kind": "named",
1318+
"value": "foo-bar",
1319+
},
1320+
},
1321+
],
1322+
},
1323+
]
1324+
`)
1325+
})
1326+
12971327
it('should parse a functional variant starting with @ and a modifier', () => {
12981328
let utilities = new Utilities()
12991329
utilities.static('flex', () => [])

packages/tailwindcss/src/candidate.ts

Lines changed: 8 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -745,14 +745,6 @@ function* findRoots(input: string, exists: (input: string) => boolean): Iterable
745745
// Otherwise test every permutation of the input by iteratively removing
746746
// everything after the last dash.
747747
let idx = input.lastIndexOf('-')
748-
if (idx === -1) {
749-
// Variants starting with `@` are special because they don't need a `-`
750-
// after the `@` (E.g.: `@-lg` should be written as `@lg`).
751-
if (input[0] === '@' && exists('@')) {
752-
yield ['@', input.slice(1)]
753-
}
754-
return
755-
}
756748

757749
// Determine the root and value by testing permutations of the incoming input.
758750
//
@@ -761,7 +753,7 @@ function* findRoots(input: string, exists: (input: string) => boolean): Iterable
761753
// `bg-red-500` -> No match
762754
// `bg-red` -> No match
763755
// `bg` -> Match
764-
do {
756+
while (idx > 0) {
765757
let maybeRoot = input.slice(0, idx)
766758

767759
if (exists(maybeRoot)) {
@@ -776,5 +768,11 @@ function* findRoots(input: string, exists: (input: string) => boolean): Iterable
776768
}
777769

778770
idx = input.lastIndexOf('-', idx - 1)
779-
} while (idx > 0)
771+
}
772+
773+
// Try '@' variant after permutations. This allows things like `@max` of `@max-foo-bar`
774+
// to match before looking for `@`.
775+
if (input[0] === '@' && exists('@')) {
776+
yield ['@', input.slice(1)]
777+
}
780778
}

packages/tailwindcss/src/variants.test.ts

Lines changed: 44 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2074,6 +2074,7 @@ test('container queries', async () => {
20742074
css`
20752075
@theme {
20762076
--container-lg: 1024px;
2077+
--container-foo-bar: 1440px;
20772078
}
20782079
@tailwind utilities;
20792080
`,
@@ -2082,20 +2083,38 @@ test('container queries', async () => {
20822083
'@lg/name:flex',
20832084
'@[123px]:flex',
20842085
'@[456px]/name:flex',
2086+
'@foo-bar:flex',
2087+
'@foo-bar/name:flex',
20852088

20862089
'@min-lg:flex',
20872090
'@min-lg/name:flex',
20882091
'@min-[123px]:flex',
20892092
'@min-[456px]/name:flex',
2093+
'@min-foo-bar:flex',
2094+
'@min-foo-bar/name:flex',
20902095

20912096
'@max-lg:flex',
20922097
'@max-lg/name:flex',
20932098
'@max-[123px]:flex',
20942099
'@max-[456px]/name:flex',
2100+
'@max-foo-bar:flex',
2101+
'@max-foo-bar/name:flex',
20952102
],
20962103
),
20972104
).toMatchInlineSnapshot(`
2098-
"@container name not (min-width: 1024px) {
2105+
"@container name not (min-width: 1440px) {
2106+
.\\@max-foo-bar\\/name\\:flex {
2107+
display: flex;
2108+
}
2109+
}
2110+
2111+
@container not (min-width: 1440px) {
2112+
.\\@max-foo-bar\\:flex {
2113+
display: flex;
2114+
}
2115+
}
2116+
2117+
@container name not (min-width: 1024px) {
20992118
.\\@max-lg\\/name\\:flex {
21002119
display: flex;
21012120
}
@@ -2153,6 +2172,30 @@ test('container queries', async () => {
21532172
.\\@min-lg\\:flex {
21542173
display: flex;
21552174
}
2175+
}
2176+
2177+
@container name (min-width: 1440px) {
2178+
.\\@foo-bar\\/name\\:flex {
2179+
display: flex;
2180+
}
2181+
}
2182+
2183+
@container (min-width: 1440px) {
2184+
.\\@foo-bar\\:flex {
2185+
display: flex;
2186+
}
2187+
}
2188+
2189+
@container name (min-width: 1440px) {
2190+
.\\@min-foo-bar\\/name\\:flex {
2191+
display: flex;
2192+
}
2193+
}
2194+
2195+
@container (min-width: 1440px) {
2196+
.\\@min-foo-bar\\:flex {
2197+
display: flex;
2198+
}
21562199
}"
21572200
`)
21582201
})

0 commit comments

Comments
 (0)