No description
Find a file
Robin Malfait 77b3cb5318
Handle @variant inside @custom-variant (#18885)
This PR fixes an issue where you cannot use `@variant` inside a
`@custom-variant`. While you can use `@variant` in normal CSS, you
cannot inside of `@custom-variant`. Today this silently fails and emits
invalid CSS.
```css
@custom-variant dark {
  @variant data-dark {
    @slot;
  }
}
```
```html
<div class="dark:flex"></div>
```

Would result in:
```css
.dark\:flex {
  @variant data-dark {
    display: flex;
  }
}
```

To solve it we have 3 potential solutions:

1. Consider it user error — but since it generates CSS and you don't
really get an error you could be shipping broken CSS unknowingly.
1. We could try and detect this and not generate CSS for this and
potentially show a warning.
1. We could make it work as expected — which is what this PR does.

Some important notes:

1. The evaluation of the `@custom-variant` only happens when you
actually need it. That means that `@variant` inside `@custom-variant`
will always have the implementation of the last definition of that
variant.

In other words, if you use `@variant hover` inside a `@custom-variant`,
and later you override the `hover` variant, the `@custom-variant` will
use the new implementation.
1. If you happen to introduce a circular dependency, then an error will
be thrown during the build step.

You can consider it a bug fix or a new feature it's a bit of a gray
area. But
one thing that is cool about this is that you can ship a plugin that
looks like
this:
```css
@custom-variant hocus {
  @variant hover {
    @slot;
  }

  @variant focus {
    @slot;
  }
}
```

And it will use the implementation of `hover` and `focus` that the user
has defined. So if they have a custom `hover` or `focus` variant it will
just work.

By default `hocus:underline` would generate:
```css
@media (hover: hover) {
  .hocus\:underline:hover {
    text-decoration-line: underline;
  }
}

.hocus\:underline:focus {
  text-decoration-line: underline;
}
```

But if you have a custom `hover` variant like:
```css
@custom-variant hover (&:hover);
```

Then `hocus:underline` would generate:
```css
.hocus\:underline:hover, .hocus\:underline:focus {
  text-decoration-line: underline;
}
```

### Test plan

1. Existing tests pass
2. Added tests with this new functionality handled
3. Made sure to add a test for circular dependencies + error message
4. Made sure that if you "fix" the circular dependency (by overriding a
variant) that everything is generated as expected.

Fixes: https://github.com/tailwindlabs/tailwindcss/issues/18524
2025-09-05 12:24:11 +00:00
.github Create FUNDING.yml 2025-07-02 13:22:16 -04:00
crates Handle ' syntax in ClojureScript when extracting classes (#18888) 2025-09-05 14:17:07 +02:00
integrations chore: remove redundant words (#18853) 2025-09-02 08:13:15 +00:00
packages Handle @variant inside @custom-variant (#18885) 2025-09-05 12:24:11 +00:00
patches Upgrade lightningcss to 1.30.1 (#18037) 2025-05-15 13:16:02 +02:00
playgrounds 🚨 [security] Update all of nextjs 15.4.4 → 15.4.7 (patch) (#18838) 2025-09-01 11:24:56 +02:00
scripts Add experimental @tailwindcss/oxide-wasm32-wasi (#17558) 2025-04-11 17:19:55 +02:00
.gitignore Fix slow unit test (#17465) 2025-03-31 15:26:01 +02:00
.npmrc introduce v4 codebase 2024-03-05 14:29:15 +01:00
.prettierignore Hoist oxide/crates to just crates (#13333) 2024-03-23 09:00:48 -04:00
Cargo.lock Fix HAML extraction with embedded Ruby (#17846) 2025-05-05 10:26:17 -04:00
Cargo.toml Hoist oxide/crates to just crates (#13333) 2024-03-23 09:00:48 -04:00
CHANGELOG.md Handle @variant inside @custom-variant (#18885) 2025-09-05 12:24:11 +00:00
LICENSE Add README, LICENSE, and CONTRIBUTING (#13088) 2024-03-05 14:45:39 -05:00
package.json Update @playwright/test 1.54.2 → 1.55.0 (minor) (#18823) 2025-08-29 16:16:39 +02:00
pnpm-lock.yaml 🚨 [security] Update all of nextjs 15.4.4 → 15.4.7 (patch) (#18838) 2025-09-01 11:24:56 +02:00
pnpm-workspace.yaml feat: add Vite 7 support to the @tailwindcss/vite plugin (#18384) 2025-06-24 12:31:17 -04:00
README.md Update README.md (#18434) 2025-07-02 16:40:30 -04:00
rust-toolchain.toml Improve Oxide candidate extractor [0] (#16306) 2025-03-05 11:55:24 +01:00
turbo.json Fix segmentation fault when loading @tailwindcss/oxide in a Worker thread (#17276) 2025-03-18 16:28:20 -04:00
vitest.workspace.ts introduce v4 codebase 2024-03-05 14:29:15 +01:00

Tailwind CSS

A utility-first CSS framework for rapidly building custom user interfaces.

Build Status Total Downloads Latest Release License


Documentation

For full documentation, visit tailwindcss.com.

Community

For help, discussion about best practices, or feature ideas:

Discuss Tailwind CSS on GitHub

Contributing

If you're interested in contributing to Tailwind CSS, please read our contributing docs before submitting a pull request.