Skip to content

Commit a0c2186

Browse files
Ensure escaped theme variables are handled correctly
1 parent ea24995 commit a0c2186

File tree

6 files changed

+39
-11
lines changed

6 files changed

+39
-11
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
1010
### Fixed
1111

1212
- Only generate positive `grid-cols-*` and `grid-rows-*` utilities ([#16020](https://github.com/tailwindlabs/tailwindcss/pull/16020))
13+
- Ensure escaped theme variables are handled correctly
1314

1415
## [4.0.1] - 2025-01-29
1516

packages/tailwindcss/src/compat/apply-config-to-theme.ts

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
import type { DesignSystem } from '../design-system'
22
import { ThemeOptions } from '../theme'
3-
import { escape } from '../utils/escape'
43
import type { ResolvedConfig } from './config/types'
54

65
function resolveThemeValue(value: unknown, subValue: string | null = null): string | null {
@@ -55,7 +54,7 @@ export function applyConfigToTheme(
5554
if (!name) continue
5655

5756
designSystem.theme.add(
58-
`--${escape(name)}`,
57+
`--${name}`,
5958
'' + value,
6059
ThemeOptions.INLINE | ThemeOptions.REFERENCE | ThemeOptions.DEFAULT,
6160
)

packages/tailwindcss/src/compat/plugin-api.test.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1425,7 +1425,7 @@ describe('theme', async () => {
14251425
:root, :host {
14261426
--width-1: 0.25rem;
14271427
--width-1\\/2: 60%;
1428-
--width-1\\.5: 0.375rem;
1428+
--width-1_5: 0.375rem;
14291429
--width-2_5: 0.625rem;
14301430
}
14311431
"
@@ -1482,7 +1482,7 @@ describe('theme', async () => {
14821482
:root, :host {
14831483
--width-1: 0.25rem;
14841484
--width-1\\/2: 60%;
1485-
--width-1\\.5: 0.375rem;
1485+
--width-1_5: 0.375rem;
14861486
--width-2_5: 0.625rem;
14871487
}
14881488
"

packages/tailwindcss/src/index.test.ts

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -152,6 +152,35 @@ describe('compiling CSS', () => {
152152
`)
153153
})
154154

155+
test('unescapes theme variables and handles dots as underscore', async () => {
156+
expect(
157+
await compileCss(
158+
css`
159+
@theme {
160+
--spacing-*: initial;
161+
--spacing-1\.5: 2.5rem;
162+
--spacing-foo\/bar: 3rem;
163+
}
164+
@tailwind utilities;
165+
`,
166+
['m-1.5', 'm-foo/bar'],
167+
),
168+
).toMatchInlineSnapshot(`
169+
":root, :host {
170+
--spacing-1_5: 2.5rem;
171+
--spacing-foo\\/bar: 3rem;
172+
}
173+
174+
.m-1\\.5 {
175+
margin: var(--spacing-1_5);
176+
}
177+
178+
.m-foo\\/bar {
179+
margin: var(--spacing-foo\\/bar);
180+
}"
181+
`)
182+
})
183+
155184
test('adds vendor prefixes', async () => {
156185
expect(
157186
await compileCss(

packages/tailwindcss/src/index.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ import * as CSS from './css-parser'
2727
import { buildDesignSystem, type DesignSystem } from './design-system'
2828
import { Theme, ThemeOptions } from './theme'
2929
import { createCssUtility } from './utilities'
30+
import { escape, unescape } from './utils/escape'
3031
import { segment } from './utils/segment'
3132
import { compoundsForSelectors, IS_VALID_VARIANT_NAME } from './variants'
3233
export type Config = UserConfig
@@ -461,7 +462,7 @@ async function parseCss(
461462

462463
if (child.kind === 'comment') return
463464
if (child.kind === 'declaration' && child.property.startsWith('--')) {
464-
theme.add(child.property, child.value ?? '', themeOptions)
465+
theme.add(unescape(child.property), child.value ?? '', themeOptions)
465466
return
466467
}
467468

@@ -520,7 +521,7 @@ async function parseCss(
520521

521522
for (let [key, value] of theme.entries()) {
522523
if (value.options & ThemeOptions.REFERENCE) continue
523-
nodes.push(decl(key, value.value))
524+
nodes.push(decl(escape(key), value.value))
524525
}
525526

526527
let keyframesRules = theme.getKeyframes()

packages/tailwindcss/src/theme.ts

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -41,9 +41,7 @@ export class Theme {
4141
) {}
4242

4343
add(key: string, value: string, options = ThemeOptions.NONE): void {
44-
if (key.endsWith('\\*')) {
45-
key = key.slice(0, -2) + '*'
46-
}
44+
key = key.replaceAll('.', '_')
4745

4846
if (key.endsWith('-*')) {
4947
if (value !== 'initial') {
@@ -150,7 +148,7 @@ export class Theme {
150148
for (let namespace of themeKeys) {
151149
let themeKey =
152150
candidateValue !== null
153-
? (escape(`${namespace}-${candidateValue.replaceAll('.', '_')}`) as ThemeKey)
151+
? (`${namespace}-${candidateValue.replaceAll('.', '_')}` as ThemeKey)
154152
: namespace
155153

156154
if (!this.values.has(themeKey)) continue
@@ -167,7 +165,7 @@ export class Theme {
167165
return null
168166
}
169167

170-
return `var(${this.#prefixKey(themeKey)})`
168+
return `var(${escape(this.#prefixKey(themeKey))})`
171169
}
172170

173171
resolve(candidateValue: string | null, themeKeys: ThemeKey[]): string | null {

0 commit comments

Comments
 (0)