Skip to content

Commit bc88958

Browse files
Add support for the CSS theme() function (tailwindlabs#14177)
This PR adds the CSS `theme()` function to Tailwind V4. It's intended use is to get the raw value of a theme variable. This can be handy when trying to reference theme values in places where `var()` is not supported, for example: ```css @media (min-width: theme(--breakpoint-md)) { /*...*/ } ``` The CSS `theme()` function is backward compatible with Tailwind V3 which means that it can also be used with the old key path syntax, like: `theme(colors.red.500)`. The lookup for this is shared with the plugin `theme()` function and this PR adds a bunch of edge cases to validate the backward compatibility. Here are a few interesting cases that we found to be valid in Tailwind V3 and are now also valid in Tailwind V4: ```js // First argument can be inside quotes theme('colors.red.500') // Square brackets are valid separators in V3, even when chained with dots theme(color[red].500) // Slashes can be used for adding opacity to colors. This can also be inside quotes theme('colors.red.500 / 75%') // Oh yeah and there's also the tuple syntax for accessing v3 scoped variables theme(fontSize.xs[1].lineHeight) // themes can also define fallback values which could be theme calls again... theme(colors.red.unknown / 75%, theme(colors.red.500 / 25%)) // ... or list of values: theme(fontFamily.sans, 'Helvetica Neue', Helvetica, sans-serif) // Theme function can also be used in candidate class names... sm:[--color:theme(colors.red[500]) // ... and of course @media queries @media (min-width: theme(breakpoint.md)) and (max-width: theme(--breakpoint-lg)) ``` The way this is implemented right now is by adding a separate walk that scans all declaration values. If these values look like they could have a `theme()` function call, we will parse these values using a new `ValueParser` into a small AST that can be used to substitute function calls.
1 parent 30bbe51 commit bc88958

File tree

15 files changed

+1187
-30
lines changed

15 files changed

+1187
-30
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
1515
- Add support for `addComponents`, `matchComponents`, `prefix` plugin APIs ([#14221](https://github.com/tailwindlabs/tailwindcss/pull/14221))
1616
- Add support for `tailwindcss/colors` and `tailwindcss/defaultTheme` exports for use with plugins ([#14221](https://github.com/tailwindlabs/tailwindcss/pull/14221))
1717
- Add support for the `@tailwindcss/typography` and `@tailwindcss/forms` plugins ([#14221](https://github.com/tailwindlabs/tailwindcss/pull/14221))
18+
- Add support for the `theme()` function in CSS and class names ([#14177](https://github.com/tailwindlabs/tailwindcss/pull/14177))
1819

1920
### Fixed
2021

packages/tailwindcss/src/ast.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ export type Rule = {
77
export type Declaration = {
88
kind: 'declaration'
99
property: string
10-
value: string
10+
value: string | undefined
1111
important: boolean
1212
}
1313

packages/tailwindcss/src/compat/config/resolve-config.test.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -181,15 +181,15 @@ test('theme keys can read from the CSS theme', ({ expect }) => {
181181
theme: {
182182
colors: {
183183
red: 'red',
184-
green: 'var(--color-green, green)',
184+
green: 'green',
185185
},
186186
accentColor: {
187187
red: 'red',
188-
green: 'var(--color-green, green)',
188+
green: 'green',
189189
},
190190
placeholderColor: {
191-
primary: 'var(--color-green, green)',
192-
secondary: 'var(--color-green, green)',
191+
primary: 'green',
192+
secondary: 'green',
193193
},
194194
},
195195
})

packages/tailwindcss/src/compile.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -265,7 +265,7 @@ function getPropertySort(nodes: AstNode[]) {
265265
let node = q.shift()!
266266
if (node.kind === 'declaration') {
267267
if (node.property === '--tw-sort') {
268-
let idx = GLOBAL_PROPERTY_ORDER.indexOf(node.value)
268+
let idx = GLOBAL_PROPERTY_ORDER.indexOf(node.value ?? '')
269269
if (idx !== -1) {
270270
propertySort.add(idx)
271271
break

0 commit comments

Comments
 (0)