From 193fc609899cf0c2146178b107fff08fdaab415e Mon Sep 17 00:00:00 2001 From: Robin Malfait Date: Mon, 27 Jan 2025 12:55:10 +0100 Subject: [PATCH] Ensure CSS variable shorthand uses valid CSS variables (#15738) This PR fixes an issue where we didn't always correctly validated invalid CSS variables when using the CSS variable shorthand syntax. This PR fixes that by ensuring we start with `--`. We can't validate that the variable exists at runtime, but we can validate if it looks like a valid CSS variable. We can go a step further by validating if the CSS variable is valid syntax (e.g.: all characters are valid), but we can introduce this if this is causing actual issues in projects. ``` p-(a-b) ``` Used to compile to: ```css .p-\(a-b\) { padding: var(a-b); } ``` But not anymore. --- CHANGELOG.md | 1 + packages/tailwindcss/src/candidate.test.ts | 23 ++++++++++++++++++++++ packages/tailwindcss/src/candidate.ts | 6 ++++++ 3 files changed, 30 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3660f0795..7c86bbd08 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Fixed - Remove invalid `min-w/h-none` utilities ([#15845](https://github.com/tailwindlabs/tailwindcss/pull/15845)) +- Ensure CSS variable shorthand uses valid CSS variables ([#15738](https://github.com/tailwindlabs/tailwindcss/pull/15738)) ## [4.0.0] - 2025-01-21 diff --git a/packages/tailwindcss/src/candidate.test.ts b/packages/tailwindcss/src/candidate.test.ts index 723ae0fc8..20f89a940 100644 --- a/packages/tailwindcss/src/candidate.test.ts +++ b/packages/tailwindcss/src/candidate.test.ts @@ -570,6 +570,13 @@ it('should parse a utility with an arbitrary value with parens', () => { `) }) +it('should not parse a utility with an arbitrary value with parens that does not start with --', () => { + let utilities = new Utilities() + utilities.functional('bg', () => []) + + expect(run('bg-(my-color)', { utilities })).toMatchInlineSnapshot(`[]`) +}) + it('should parse a utility with an arbitrary value including a typehint', () => { let utilities = new Utilities() utilities.functional('bg', () => []) @@ -616,6 +623,13 @@ it('should parse a utility with an arbitrary value with parens including a typeh `) }) +it('should not parse a utility with an arbitrary value with parens including a typehint that does not start with --', () => { + let utilities = new Utilities() + utilities.functional('bg', () => []) + + expect(run('bg-(color:my-color)', { utilities })).toMatchInlineSnapshot(`[]`) +}) + it('should parse a utility with an arbitrary value with parens and a fallback', () => { let utilities = new Utilities() utilities.functional('bg', () => []) @@ -888,6 +902,8 @@ it('should not parse invalid arbitrary values in variants', () => { 'data-foo-(--value)/(number:--mod):flex', 'data-foo(--value)/(number:--mod):flex', + + 'data-(value):flex', ]) { expect(run(candidate, { utilities, variants })).toEqual([]) } @@ -945,6 +961,13 @@ it('should parse a utility with an implicit variable as the modifier using the s `) }) +it('should not parse a utility with an implicit invalid variable as the modifier using the shorthand', () => { + let utilities = new Utilities() + utilities.functional('bg', () => []) + + expect(run('bg-red-500/(value)', { utilities })).toMatchInlineSnapshot(`[]`) +}) + it('should parse a utility with an implicit variable as the modifier that is important', () => { let utilities = new Utilities() utilities.functional('bg', () => []) diff --git a/packages/tailwindcss/src/candidate.ts b/packages/tailwindcss/src/candidate.ts index abb230da0..8238dfc2f 100644 --- a/packages/tailwindcss/src/candidate.ts +++ b/packages/tailwindcss/src/candidate.ts @@ -517,6 +517,9 @@ function parseModifier(modifier: string): CandidateModifier | null { // ^^ if (arbitraryValue.length === 0 || arbitraryValue.trim().length === 0) return null + // Arbitrary values must start with `--` since it represents a CSS variable. + if (arbitraryValue[0] !== '-' && arbitraryValue[1] !== '-') return null + return { kind: 'arbitrary', value: `var(${arbitraryValue})`, @@ -651,6 +654,9 @@ export function parseVariant(variant: string, designSystem: DesignSystem): Varia // ^^ if (arbitraryValue.length === 0 || arbitraryValue.trim().length === 0) return null + // Arbitrary values must start with `--` since it represents a CSS variable. + if (arbitraryValue[0] !== '-' && arbitraryValue[1] !== '-') return null + return { kind: 'functional', root,