Skip to content

Commit fa3f45f

Browse files
Don’t output CSS objects with false or undefined in the AST (#18571)
Fixes tailwindlabs/tailwindcss-typography#384 Basically when addUtilities/addComponents/matchUtilities/matchComponents saw a value of `false` it was being output instead of being discarded like it was in v3. The types really require these to be strings but for things like the typography plugin this isn't really carried through from its theme config so it was easy to put anything in there and not realize it doesn't match the expected types. Basically this: ```js addUtilities({ '.foo': { a: 'red', 'z-index': 0, '.bar': false, '.baz': null, // this one already worked '.qux': undefined, }, }) ``` Now works like it did in v3 and omits `.bar`, `.baz`, and `.qux`
1 parent 847ed1e commit fa3f45f

File tree

3 files changed

+48
-1
lines changed

3 files changed

+48
-1
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
1818
- Center the dropdown icon added to an input with a paired datalist ([#18511](https://github.com/tailwindlabs/tailwindcss/pull/18511))
1919
- Extract candidates in Slang templates ([#18565](https://github.com/tailwindlabs/tailwindcss/pull/18565))
2020
- Improve error messages when encountering invalid functional utility names ([#18568](https://github.com/tailwindlabs/tailwindcss/pull/18568))
21+
- Don’t output CSS objects with false or undefined in the AST ([#18571](https://github.com/tailwindlabs/tailwindcss/pull/18571))
2122

2223
## [4.1.11] - 2025-06-26
2324

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

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3360,6 +3360,45 @@ describe('addUtilities()', () => {
33603360
}"
33613361
`)
33623362
})
3363+
3364+
test('values that are `false`, `null`, or `undefined` are discarded from CSS object ASTs', async () => {
3365+
let compiled = await compile(
3366+
css`
3367+
@plugin "my-plugin";
3368+
@tailwind utilities;
3369+
`,
3370+
{
3371+
async loadModule(id, base) {
3372+
return {
3373+
path: '',
3374+
base,
3375+
module: ({ addUtilities }: PluginAPI) => {
3376+
addUtilities({
3377+
'.foo': {
3378+
a: 'red',
3379+
// @ts-ignore: While this isn't valid per the types this did work in v3
3380+
'z-index': 0,
3381+
// @ts-ignore
3382+
'.bar': false,
3383+
// @ts-ignore
3384+
'.baz': null,
3385+
// @ts-ignore
3386+
'.qux': undefined,
3387+
},
3388+
})
3389+
},
3390+
}
3391+
},
3392+
},
3393+
)
3394+
3395+
expect(compiled.build(['foo']).trim()).toMatchInlineSnapshot(`
3396+
".foo {
3397+
a: red;
3398+
z-index: 0;
3399+
}"
3400+
`)
3401+
})
33633402
})
33643403

33653404
describe('matchUtilities()', () => {

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

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -540,6 +540,13 @@ export function objectToAst(rules: CssInJs | CssInJs[]): AstNode[] {
540540
let entries = rules.flatMap((rule) => Object.entries(rule))
541541

542542
for (let [name, value] of entries) {
543+
if (value === null || value === undefined) continue
544+
545+
// @ts-expect-error
546+
// We do not want `false` present in the types but still need to discard these nodes for
547+
// compatibility purposes
548+
if (value === false) continue
549+
543550
if (typeof value !== 'object') {
544551
if (!name.startsWith('--')) {
545552
if (value === '@slot') {
@@ -561,7 +568,7 @@ export function objectToAst(rules: CssInJs | CssInJs[]): AstNode[] {
561568
ast.push(rule(name, objectToAst(item)))
562569
}
563570
}
564-
} else if (value !== null) {
571+
} else {
565572
ast.push(rule(name, objectToAst(value)))
566573
}
567574
}

0 commit comments

Comments
 (0)