Do not allow variants to end with - or _ (#18872)

This PR is a followup of #18867, but this time we won't allow
`@custom-variant` to end with `-` or `_`.

The same reasoning applies here where Oxide doesn't pick this up but
Intellisense and Tailwind CSS' core does.

---------

Co-authored-by: Jordan Pittman <thecrypticace@gmail.com>
This commit is contained in:
Robin Malfait 2025-09-03 17:30:54 +02:00 • committed by GitHub
parent 54c3f308e9
commit 65dc530f05
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 26 additions and 19 deletions

View file

@ -22,7 +22,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Hide internal fields from completions in `matchUtilities` ([#18820](https://github.com/tailwindlabs/tailwindcss/pull/18820))
- Ignore `.vercel` folders by default (can be overridden by `@source …` rules) ([#18855](https://github.com/tailwindlabs/tailwindcss/pull/18855))
- Consider variants starting with `@-` to be invalid (e.g. `@-2xl:flex`) ([#18869](https://github.com/tailwindlabs/tailwindcss/pull/18869))
- Do not allow custom variants to start with a `-` ([#18867](https://github.com/tailwindlabs/tailwindcss/pull/18867))
- Do not allow custom variants to start or end with a `-` or `_` ([#18867](https://github.com/tailwindlabs/tailwindcss/pull/18867), [#18872](https://github.com/tailwindlabs/tailwindcss/pull/18872))
- Upgrade: Migrate `aria` theme keys to `@custom-variant` ([#18815](https://github.com/tailwindlabs/tailwindcss/pull/18815))
- Upgrade: Migrate `data` theme keys to `@custom-variant` ([#18816](https://github.com/tailwindlabs/tailwindcss/pull/18816))
- Upgrade: Migrate `supports` theme keys to `@custom-variant` ([#18817](https://github.com/tailwindlabs/tailwindcss/pull/18817))

View file

@ -3772,24 +3772,31 @@ describe('@custom-variant', () => {
)
})
test('@custom-variant cannot contain dashes on its own', () => {
return expect(
compileCss(css`
@custom-variant - (&.dash);
`),
).rejects.toThrowErrorMatchingInlineSnapshot(
`[Error: \`@custom-variant -\` defines an invalid variant name. Variants should only contain alphanumeric, dashes, or underscore characters and start with a lowercase letter or number.]`,
)
})
test.each([
// Cannot be a dash on its own
[`@custom-variant - (&);`],
// Cannot be multiple dashes on their own
[`@custom-variant --- (&);`],
// Cannot be an underscore on its own
[`@custom-variant _ (&);`],
// Cannot be multiple underscores on their own
[`@custom-variant ___ (&);`],
test('@custom-variant cannot contain multiple dashes on their own', () => {
return expect(
compileCss(css`
@custom-variant --- (&.dashed);
`),
).rejects.toThrowErrorMatchingInlineSnapshot(
`[Error: \`@custom-variant ---\` defines an invalid variant name. Variants should only contain alphanumeric, dashes, or underscore characters and start with a lowercase letter or number.]`,
)
// Cannot start with a dash
[`@custom-variant -foo (&);`],
[`@custom-variant --foo (&);`],
// Cannot start with an underscore
[`@custom-variant _foo (&);`],
[`@custom-variant __foo (&);`],
// Cannot end with a dash
[`@custom-variant foo- (&);`],
[`@custom-variant foo-- (&);`],
// Cannot end with an underscore
[`@custom-variant foo_ (&);`],
[`@custom-variant foo__ (&);`],
])('@custom-variant must have a valid name', (input) => {
return expect(compileCss(input)).rejects.toThrowError()
})
test('@custom-variant must not container special characters', () => {

View file

@ -18,7 +18,7 @@ import { DefaultMap } from './utils/default-map'
import { isPositiveInteger } from './utils/infer-data-type'
import { segment } from './utils/segment'
export const IS_VALID_VARIANT_NAME = /^@?[a-z0-9][a-zA-Z0-9_-]*$/
export const IS_VALID_VARIANT_NAME = /^@?[a-z0-9][a-zA-Z0-9_-]*(?<![_-])$/
type VariantFn<T extends Variant['kind']> = (
rule: Rule,