From a781988032aff4af0b367504824fb79b3bb440b1 Mon Sep 17 00:00:00 2001 From: Casey Corcoran Date: Mon, 13 Apr 2026 11:55:34 -0500 Subject: [PATCH] Fix negation of theme() in arbitrary values When using a negative modifier with theme() inside an arbitrary value (e.g. `-ms-[theme(margin.1)]`), no CSS was generated because `negateValue` did not recognize `theme()` as a negatable function. Added `theme` to the list of numeric functions in `negateValue` so that `theme()` values are wrapped in `calc(... * -1)` and then resolved by the PostCSS theme() plugin downstream. --- src/util/negateValue.js | 2 +- tests/arbitrary-values.test.js | 19 +++++++++++++++++++ tests/negateValue.test.js | 4 ++++ 3 files changed, 24 insertions(+), 1 deletion(-) diff --git a/src/util/negateValue.js b/src/util/negateValue.js index b1cdf78eaee5..08337220d108 100644 --- a/src/util/negateValue.js +++ b/src/util/negateValue.js @@ -14,7 +14,7 @@ export default function negateValue(value) { // var() isn't inherently a numeric function but we support it anyway // The trigonometric functions are omitted because you'll need to use calc(…) with them _anyway_ // to produce generally useful results and that will be covered already - let numericFunctions = ['var', 'calc', 'min', 'max', 'clamp'] + let numericFunctions = ['var', 'calc', 'min', 'max', 'clamp', 'theme'] for (const fn of numericFunctions) { if (value.includes(`${fn}(`)) { diff --git a/tests/arbitrary-values.test.js b/tests/arbitrary-values.test.js index 594980803235..8e3708ec1123 100644 --- a/tests/arbitrary-values.test.js +++ b/tests/arbitrary-values.test.js @@ -354,6 +354,25 @@ it('should be possible to read theme values in arbitrary values (without quotes) }) }) +it('should be possible to negate theme values in arbitrary values with negative modifier', () => { + let config = { + content: [{ raw: html`
` }], + theme: { + spacing: { + 1: '0.25rem', + }, + }, + } + + return run('@tailwind utilities', config).then((result) => { + return expect(result.css).toMatchFormattedCss(css` + .-mt-\[theme\(spacing\.1\)\] { + margin-top: -0.25rem; + } + `) + }) +}) + it('should be possible to read theme values in arbitrary values (with quotes)', () => { let config = { content: [{ raw: html`
` }], diff --git a/tests/negateValue.test.js b/tests/negateValue.test.js index c31741d48876..265d2d3d9489 100644 --- a/tests/negateValue.test.js +++ b/tests/negateValue.test.js @@ -12,3 +12,7 @@ test('values that cannot be negated become undefined', () => { expect(negateValue('auto')).toBeUndefined() expect(negateValue('cover')).toBeUndefined() }) + +test('it negates theme() function calls', () => { + expect(negateValue('theme(margin.1)')).toEqual('calc(theme(margin.1) * -1)') +})