Skip to content

Invalid variable shorthand modifier replacement in modifiers #17888

Closed
@brandonmcconnell

Description

@brandonmcconnell

Invalid variable shorthand modifier replacement in modifiers (_ -> )

Technical Configuration
What version of Tailwind CSS are you using?
v4.1.5
What build tool (or framework if it abstracts the build tool) are you using?
Tailwind Play
What version of Node.js are you using?
N/A
What browser are you using?
Chrome
What operating system are you using?
macOS

Reproduction URL

https://play.tailwindcss.com/YvIekuzVRd

Description:

Tailwind CSS v4 handles underscores inside the arbitrary variable shorthand syntax (...) inconsistently depending on whether it's used as a utility's value or as a modifier.

Expected Behavior:

When using the (...) shorthand for a CSS variable containing underscores, such as (--my_variable), the underscores should be consistently preserved and wrapped in var(), regardless of whether it's used directly as a utility value or as a modifier following a /. The expected CSS output should be var(--my_variable).

Actual Behavior:

  1. Utility Value: When used directly as part of a utility (e.g., p-(--x_x)), the underscores are correctly preserved, resulting in var(--x_x).
  2. Modifier Value: When used as a modifier (e.g., test/(--x_x)), the underscores within the variable name are incorrectly replaced with spaces before being wrapped in var(), resulting in var(--x x).

Possible Cause (Analysis):

This seems related to the order of operations during parsing.

  • For utilities -(...), the variable context seems to be recognized before or during the call to the internal decodeArbitraryValue function, allowing its specific rule for preserving underscores within var() arguments or -- names to take effect.
  • For modifiers /(...), the internal parseModifier function appears to call decodeArbitraryValue on the raw extracted content (--x_x) first, causing default underscore-to-space replacement. Only after this decoding step is the (now space-containing) result wrapped in var().

This inconsistency makes the shorthand syntax unreliable when used within modifiers.

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions