Skip to content

Properly negate custom variants with @container when used with not-*#20059

Merged
RobinMalfait merged 7 commits into
mainfrom
fix/issue-20058
May 14, 2026
Merged

Properly negate custom variants with @container when used with not-*#20059
RobinMalfait merged 7 commits into
mainfrom
fix/issue-20058

Conversation

@RobinMalfait
Copy link
Copy Markdown
Member

This PR fixes an issue where a custom variant declared with a @container wasn't properly negated when using it in combination with the not-* variant.

Given this CSS:

@custom-variant has-a {
  @container style(--a) {
    @slot;
  }
}

If you then used not-has-a:flex, then the following CSS was produced:

.not-has-a\:flex {
  @container style(--a) not {
    display: flex;
  }
}

But we expect the not to be in the correct location:

.not-has-a\:flex {
  @container not style(--a) {
    display: flex;
  }
}

The issue was that we did some string related checks, and we assumed that the query part of the @container (style(--a)) had to start with a ( character.

To fix this, we now parse the value to an AST, and verify the AST shape before manipulating it. This now checks whether the query part is a function (both (…) and style(…) are considered functions).

Also added some additional tests that were already handled, these cases look like:

  • @container {query}
  • @container not {query}
  • @container {name} not {query}
  • @container {name} {query}

Fixes: #20058

Test plan

  1. Added a failing test for the use case of the linked issue.
  2. Added a few more additional tests to explicitly track some use cases we handled already but didn't track via tests.
  3. All other tests still pass as expected.

We parse the condition into a Value AST. This could also be done by the
SelectorParser instead of the ValueParser, but the ValueParser is a bit
simpler and enough for what we need for now.

Once we have the AST, we can check data of the tree to determine what
kind of shape we are in. The query of a `@container` looks like `(…)`
or `style(…)` for example, and in both cases those are functions, the
latter case wasn't handled properly.
@RobinMalfait RobinMalfait requested a review from a team as a code owner May 14, 2026 21:52
@greptile-apps
Copy link
Copy Markdown
Contributor

greptile-apps Bot commented May 14, 2026

Confidence Score: 5/5

Safe to merge — the change is a well-scoped fix for a specific @container style(…) negation bug, all existing tests continue to pass, and four new snapshot tests cover every grammar shape.

The refactoring from string-character inspection to AST-based matching is correct for all valid CSS @container inputs. The length guards sufficiently protect every indexed AST access, the four structural branches are mutually exclusive and exhaustive for real-world input, and the fallback safely handles any unforeseen edge case. No logic regressions were found.

No files require special attention.

Reviews (2): Last reviewed commit: "ensure ast contains at least x amount of..." | Re-trigger Greptile

Comment thread packages/tailwindcss/src/variants.ts
Comment thread packages/tailwindcss/src/variants.ts
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented May 14, 2026

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: a901f3fc-361a-464a-9f40-132aae8d16ba

📥 Commits

Reviewing files that changed from the base of the PR and between 0e88445 and e72f72d.

📒 Files selected for processing (2)
  • CHANGELOG.md
  • packages/tailwindcss/src/variants.ts
✅ Files skipped from review due to trivial changes (1)
  • CHANGELOG.md
🚧 Files skipped from review as they are similar to previous changes (1)
  • packages/tailwindcss/src/variants.ts

Walkthrough

The PR updates Tailwind's variant negation logic to correctly handle @container queries. negateConditions was rewritten to parse @container condition values with ValueParser and produce proper negated @container at-rules while retaining simpler handling for @media, @supports, and other conditional rules. A new Vitest inline-snapshot test verifies not-has-* container variants generate the expected negated and non-negated CSS.

🚥 Pre-merge checks | ✅ 4
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately describes the main change: fixing negation of custom variants with @container when used with not-*.
Description check ✅ Passed The description clearly explains the issue, the fix, and the test approach, directly relating to the changeset.
Linked Issues check ✅ Passed The PR fixes issue #20058 by implementing proper negation of @container queries in custom variants via AST parsing instead of string checks.
Out of Scope Changes check ✅ Passed All changes are in-scope: variants.ts implements the fix, variants.test.ts adds comprehensive tests, and CHANGELOG.md documents the fix.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

Warning

There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure.

🔧 ESLint

If the error stems from missing dependencies, add them to the package.json file. For unrecoverable errors (e.g., due to private dependencies), disable the tool in the CodeRabbit configuration.

ESLint skipped: no ESLint configuration detected in root package.json. To enable, add eslint to devDependencies.


Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@packages/tailwindcss/src/variants.ts`:
- Around line 381-418: The parsing code uses ValueParser.parse(condition) into
ast and then indexes ast[0], ast[2], and ast[4] without checking for their
existence; update the branches in the container variant handling (the checks
that read ast[0].kind, ast[2].kind, ast[4].kind) to first guard that the array
has the required length and that ast[index] is defined before accessing
.kind/.value (e.g., check ast[0], ast[2], ast[4] truthiness and ast.length >=
required index+1), and only then perform the existing kind/value comparisons and
splices; if the guards fail, fall back to the safe default behavior (return the
original condition or the existing fallback path) so malformed or empty
conditions like "" or "@container foo" do not throw.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: a219861d-0320-4093-9166-1acc4c2ea904

📥 Commits

Reviewing files that changed from the base of the PR and between 460a008 and 0e88445.

📒 Files selected for processing (2)
  • packages/tailwindcss/src/variants.test.ts
  • packages/tailwindcss/src/variants.ts

Comment thread packages/tailwindcss/src/variants.ts Outdated
@RobinMalfait RobinMalfait merged commit 36417cb into main May 14, 2026
9 checks passed
@RobinMalfait RobinMalfait deleted the fix/issue-20058 branch May 14, 2026 22:08
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

not-* variants generate invalid CSS for container style queries

1 participant