Fixes#16636
This PR enables URL rebasing for PostCSS. Furthermore it fixes an issue
where transitive imports rebased against the importer CSS file instead
of the input CSS file. While fixing this we noticed that this is also
broken in Vite right now and that our integration test swallowed that
when testing because it did not import any Tailwind CSS code and thus
was not considered a Tailwind file.
## Test plan
- Added regression integration tests
- Also validated it against the repro of
https://github.com/tailwindlabs/tailwindcss/issues/16962:
<img width="1149" alt="Screenshot 2025-03-05 at 16 41 01"
src="https://github.com/user-attachments/assets/85396659-d3d0-48c0-b1c7-6125ff8e73ac"
/>
---------
Co-authored-by: Robin Malfait <malfait.robin@gmail.com>
Co-authored-by: Jordan Pittman <jordan@cryptica.me>
Fixes#16725
When using `@reference "tailwindcss";` inside a separate CSS root (e.g.
Svelte `<style>` components, CSS modules, etc.), we have no guarantee
that the CSS variables will be defined in the main stylesheet (or if
there even is one). To work around potential issues with this we decided
in #16676 that we would emit all used CSS variables from the `@theme`
inside the `@reference` block.
However, this is not only a bit surprising but also unexpected in CSS
modules and Next.js that **requires CSS module files to only create
scope-able declarations**. To fix this issue, we decided to not emit CSS
variables but instead ensure all `var(…)` calls we create for theme
values in reference mode will simply have their fallback value added.
This ensures styles work as-expected even if the root Tailwind file does
not pick up the variable as being used or _if you don't add a root at
all_. Furthermore we do not duplicate any variable declarations across
your stylesheets and you still have the ability to change variables at
runtime.
## Test plan
- Updated snapshots everywhere (see diff)
- New Next.js CSS modules integration test
<!--
👋 Hey, thanks for your interest in contributing to Tailwind!
**Please ask first before starting work on any significant new
features.**
It's never a fun experience to have your pull request declined after
investing a lot of time and effort into a new feature. To avoid this
from happening, we request that contributors create an issue to first
discuss any significant new features. This includes things like adding
new utilities, creating new at-rules, or adding new component examples
to the documentation.
https://github.com/tailwindcss/tailwindcss/blob/master/.github/CONTRIBUTING.md
-->
---------
Co-authored-by: Adam Wathan <adam.wathan@gmail.com>
This PR re-enables the changes necessary to remove unused theme
variables and keyframes form your CSS.
This change was initially landed as #16211 and then later reverted in
#16403 because we found some unexpected interactions with using `@apply`
and CSS variables in multi-root setups like CSS modules or Vue inline
`<style>` blocks that were no longer seeing their required variables
defined.
This issue is fixed by now ensuring that theme variables that are
defined within an `@reference "…"` boundary will still be emitted in the
generated CSS when used (as this would otherwise not generate a valid
stylesheet).
So given the following input CSS:
```css
@reference "tailwindcss";
.text-red {
@apply text-red-500;
}
```
We will now compile this to:
```css
@layer theme {
:root, :host {
--text-red-500: oklch(0.637 0.237 25.331);
}
}
.text-red {
color: var(--text-red-500);
}
```
This PR also improves the initial implementation to not mark theme
variables as used if they are only used to define other theme variables.
For example:
```css
@theme {
--font-sans:
ui-sans-serif, system-ui, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol',
'Noto Color Emoji';
--font-mono:
ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, 'Liberation Mono', 'Courier New',
monospace;
--default-font-family: var(--font-sans);
--default-mono-font-family: var(--font-mono);
}
.default-font-family {
font-family: var(--default-font-family);
}
```
This would be reduced to the following now as `--font-mono` is only used
to define another variable and never used outside the theme block:
```css
:root, :host {
--font-sans:
ui-sans-serif, system-ui, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol',
'Noto Color Emoji';
--default-font-family: var(--font-sans);
}
.default-font-family {
font-family: var(--default-font-family);
}
```
## Test plan
- See updated unit and integration tests
- Validated it works end-to-end by using a SvelteKit example
This PR fixes an issue where installing a specific version of
`@tailwindcss/postcss` and `tailwindcss` could still result in a version
mismatch. This is because we were relying on `^4.0.6` for example
instead of `4.0.6`.
This PR now pins all these versions to prevent this:
```
❯ pnpm why tailwindcss
devDependencies:
@tailwindcss/postcss 4.0.5
├─┬ @tailwindcss/node 4.0.6
│ └── tailwindcss 4.0.6
└── tailwindcss 4.0.5
```
This reverts #16211
We found some unexpected interactions with using `@apply` and CSS
variables in multi-root setups like CSS modules or Vue inline `<style>`
blocks that were broken due to that change. We plan to re-enable this
soon and include a proper fix for those scenarios.
## Test plan
- Updated snapshots
- Tested using the CLI in a new project:
<img width="1523" alt="Screenshot 2025-02-10 at 13 08 42"
src="https://github.com/user-attachments/assets/defe0858-adb3-4d61-9d2c-87166558fd68"
/>
---------
Co-authored-by: Robin Malfait <malfait.robin@gmail.com>
<!--
👋 Hey, thanks for your interest in contributing to Tailwind!
**Please ask first before starting work on any significant new
features.**
It's never a fun experience to have your pull request declined after
investing a lot of time and effort into a new feature. To avoid this
from happening, we request that contributors create an issue to first
discuss any significant new features. This includes things like adding
new utilities, creating new at-rules, or adding new component examples
to the documentation.
https://github.com/tailwindcss/tailwindcss/blob/master/.github/CONTRIBUTING.md
-->
---------
Co-authored-by: Adam Wathan <4323180+adamwathan@users.noreply.github.com>
This PR fixes an issue where if you only used `@reference` that we
didn't process Tailwind CSS features.
We have a 'quick bail check', in the PostCSS plugin to quickly bail if
we _konw_ that we don't need to handle any Tailwind CSS features. This
is useful in Next.js applications where every single CSS file will be
passed to the PostCSS plugin.
If you use custom font ins Next.js, each of those fonts will have a CSS
file as well.
Before we introduced `@reference`, we used `@import "tailwindcss"
reference`, which passed the bail check because `@import` was being
used. Now we have `@reference` which wasn't included in the list.
This is now solved.
Fixes: #16056
### Test plan
Added a failing test that is now failing after the fix.
Resolves#15799Resolves#14478
Part-of #15005
Adds a `:host` selector for the `@theme` layer. This is necessary for
the `@theme` layer to work correctly in shadow DOM.
Also updates the snapshots for the tests that were affected by this
change (in a separate commit).
## Test plan
Tested via the Vite playground:
<img width="1121" alt="Screenshot 2025-01-29 at 15 06 49"
src="https://github.com/user-attachments/assets/a7908135-5ff8-472f-a053-d2c6d5c81e1b"
/>
Additionally made sure that `@property` defaults also work across
Firefox, Chrome, and Safari (the `@property` definition from the root is
pulled in) and added a UI spec.
---------
Co-authored-by: Philipp Spiess <hello@philippspiess.com>
Upgrading `lightningcss` to fix invalid `list-style: none` conversion.
I've also reverted the change to preflight while at it, since it's no
longer necessary.
Closes#15438Closes#15560Closes#15561Closes#15562
This PR upgrades `lightningcss` to `1.29.0` and uses the [new feature
flag](304389600f)
to disable the light-dark function transpilation.
We don’t want utilities like `basis-prose`, `w-prose`, etc existing nor
a `@prose:*` variant. So we’re moving the theme key to `--max-width-*`
to align with the definition as it was in v3.
cc @adamwathan
---------
Co-authored-by: Adam Wathan <4323180+adamwathan@users.noreply.github.com>
Resolves https://github.com/tailwindlabs/tailwindcss/discussions/15387
This PR changes the Chrome target to 111. We initially picked 120
because of the unnecessary `:dir()` down-leveling but we that was maybe
a bit too recent as it was causing some necessary prefixes to not be
generated (e.g. `-webkit-background-clip`).
This PR changes it to 111 which we require for the `color-mix()`
function. To work around the `:dir()` down-leveling we also disable the
`DirSelector` lightningcss feature which is used to control this
behavior:
https://sourcegraph.com/github.com/parcel-bundler/lightningcss/-/blob/src/selector.rs?L1964-1965
This PR renames the `--aspect-ratio` theme key to `--aspect`. This is to
match what we've done with other theme keys where they match the utility
names, like `--ease` and `--leading`.
```diff
@theme {
- --aspect-ratio-retro: 4 / 3;
+ --aspect-retro: 4 / 3;
}
```
Additionally, I've also converted the existing `aspect-video` static
utility to a theme value. This will allow people to override this
utility in their own projects—something that's not possible with static
utilities. This change feels appropriate since the video aspect ratio is
subjective, unlike other static utilities like `aspect-square`.
```css
@theme {
--aspect-video: 4 / 3; /* N64 baby! */
}
```
This PR skips creating a compiler in the `@tailwindcss/postcss`
implementation if we know that the CSS file we are handling is
definitely not a Tailwind CSS file.
This is a performance improvement for initial builds where some CSS
files would've been handling by Tailwind CSS but shouldn't. E.g.: When
setting up custom fonts in Next.js applications, each font will have
it's own CSS file that is passed to `@tailwindcss/postcss`.
Since they don't contain `@import` or any other Tailwind CSS directives,
we can just skip them.
Resolves#15320Resolves#15175
Turns out that the postcss file watcher does not like our Unix based
paths and will print a warning about them. This fixes the issue by
calling `path.resolve()` to convert it back to a Windows-style absolute
path if necessary.
## Test Plan
Tested on Windows with a new Next.js 14 project. Ensured that file
reloads also still work (changes to the `tsx` file are picked up
correctly). Also ensure that the CI runs on Windows.
### Before
<img width="1178" alt="Screenshot 2024-12-06 at 13 12 23"
src="https://github.com/user-attachments/assets/70c1fe45-6983-4fb4-9889-716a0cbef03a">
### After
<img width="1196" alt="Screenshot 2024-12-06 at 13 23 24"
src="https://github.com/user-attachments/assets/0b9e3ff7-c5b6-4ccb-85a9-e7ba7aee355a">
This PR improves the `@tailwindcss/postcss` integration by using direct
AST transformations between our own AST and PostCSS's AST. This allows
us to skip a step where we convert our AST into a string, then parse it
back into a PostCSS AST.
The only downside is that we still have to print the AST into a string
if we want to optimize the CSS using Lightning CSS. Luckily this only
happens in production (`NODE_ENV=production`).
This also introduces a new private `compileAst` API, that allows us to
accept an AST as the input. This allows us to skip the PostCSS AST ->
string -> parse into our own AST step.
To summarize:
Instead of:
- Input: `PostCSS AST` -> `.toString()` -> `CSS.parse(…)` -> `Tailwind
CSS AST`
- Output: `Tailwind CSS AST` -> `toCSS(ast)` -> `postcss.parse(…)` ->
`PostCSS AST`
We will now do this instead:
- Input: `PostCSS AST` -> `transform(…)` -> `Tailwind CSS AST`
- Output: `Tailwind CSS AST` -> `transform(…)` -> `PostCSS AST`
---
Running this on Catalyst, the time spent in the `@tailwindcss/postcss`
looks like this:
- Before: median time per run: 19.407687 ms
- After: median time per run: 11.8796455 ms
This is tested on Catalyst which roughly generates ~208kb worth of CSS
in dev mode.
While it's not a lot, skipping the stringification and parsing seems to
improve this step by ~40%.
Note: these times exclude scanning the actual candidates and only time
the work needed for parsing/stringifying the CSS from and into ASTs. The
actual numbers are a bit higher because of the Oxide scanner reading
files from disk. But since that part is going to be there no matter
what, it's not fair to include it in this benchmark.
---------
Co-authored-by: Jordan Pittman <jordan@cryptica.me>
Closes#15138
This PR changes the postcss client to run in the `Once` hook instead of
`OnceExit`. This makes sure the postcss order in v4 matches that of v3.
Conceptually this also makes more sense, since we expect tailwindcss to
be run as one of the first plugins in the pipeline (where `OnceExit`
would run it almost at the end).
To make sure it's still possible to use `postcss-import` before and have
it resolve to the right paths, we also needed to change the
`postcss-fix-relative-paths` plugin to run in the `Once` order
(`postcss-import` also uses `Once` order so the order).
## Test Plan
This issue had many ways in which it can manifest. I added a unit test
to ensure the plugin order works but here's a concrete example when
using the postcss plugin in Vite.
### Before
Image `url()`s were not properly handled since the postcss plugin to
transform these was run before Tailwind CSS could generate the class for
it:
<img width="2532" alt="Screenshot 2024-12-02 at 14 55 42"
src="https://github.com/user-attachments/assets/2f23b409-1576-441d-9ffe-6f24ad6e7436">
### After
<img width="2529" alt="Screenshot 2024-12-02 at 14 53 52"
src="https://github.com/user-attachments/assets/b754c3d8-1af1-4aeb-87da-0bfc3ffecdb7">
---------
Co-authored-by: Jordan Pittman <jordan@cryptica.me>
This PR improves the performance of the `@tailwindcss/postcss` and
`@tailwindcss/vite` implementations.
The issue is that in some scenarios, if you have multiple `.css` files,
then all of the CSS files are ran through the Tailwind CSS compiler. The
issue with this is that in a lot of cases, the CSS files aren't even
related to Tailwind CSS at all.
E.g.: in a Next.js project, if you use the `next/font/local` tool, then
every font you used will be in a separate CSS file. This means that we
run Tailwind CSS in all these files as well.
That said, running Tailwind CSS on these files isn't the end of the
world because we still need to handle `@import` in case `@tailwind
utilities` is being used. However, we also run the auto source detection
logic for every CSS file in the system. This part is bad.
To solve this, this PR introduces an internal `features` to collect what
CSS features are used throughout the system (`@import`, `@plugin`,
`@apply`, `@tailwind utilities`, etc…)
The `@tailwindcss/postcss` and `@tailwindcss/vite` plugin can use that
information to decide if they can take some shortcuts or not.
---
Overall, this means that we don't run the slow parts of Tailwind CSS if
we don't need to.
---------
Co-authored-by: Adam Wathan <adam.wathan@gmail.com>
Safari has an [insane
bug](https://github.com/tailwindlabs/tailwindcss/issues/15196) where if
you register custom properties for gradient colors using the `"<color>"`
type, you attempt to transition a gradient on an element, _and_ you set
a font-size and line-height on that element that point to CSS variables
defined using `rem` units, the element size changes and shifts the
layout while the transition is happening:
https://github.com/user-attachments/assets/46eefccf-8a12-4751-8a44-54e48c54cd06
This bug goes away if you use anything other than `rem` units for the
line-height. So this PR changes all of our variables like
`--text-3xl--line-height` to use unitless relative line-height values
instead of fixed line-height values to workaround this bug. Not my
favorite change but pretty low impact because you likely aren't going to
reference those variables for much anyways.
If Safari ever fixes this bug (which is still present as of Safari 18),
it would be nice to swap these back to what they were.
Fixes#15196.
---------
Co-authored-by: Adam Wathan <4323180+adamwathan@users.noreply.github.com>
Fixes https://github.com/tailwindlabs/tailwindcss/discussions/15184,
https://github.com/tailwindlabs/tailwindcss/issues/14955
There's a strange bug in Safari < 18 where mixing a color with
`transparent` or with a gray tone, the resulting color looks as if it's
been interpolated through a red-ish color.
Here's the same blue to transparent gradient in Safari 17 using OKLAB
and OKLCH for comparison:
<img width="747" alt="image"
src="https://github.com/user-attachments/assets/1cb09b00-0d84-4284-be34-103726d8af03">
In other browsers, both of these examples look identical.
This bug also shows up when using an opacity modifier right now because
we use `in oklch` in our `color-mix(…)` calls:
<img width="744" alt="image"
src="https://github.com/user-attachments/assets/b029c5f1-0c5c-4119-80ba-dfeabe25927e">
This PR updates all of the affected places in Tailwind to use `in oklab`
instead of `in oklch` which then renders everything as expected in all
browsers.
The big unfortunate change here is changing the default behavior of
gradient utilities like `bg-linear-to-r` to use `in oklab` instead of
`in oklch`. This means you get muddier gradients by default when
creating a gradient between two regular colors (no transparent or gray),
like how they looked in v3:
<img width="740" alt="image"
src="https://github.com/user-attachments/assets/d02e7596-4c99-4ba3-b929-d2db4911c8e9">
This feels worth it though to avoid people getting bitten by this Safari
bug without realizing it, and people can always opt in to using OKLCH
with classes like `bg-linear-to-r/oklch`. The nice thing about making
this opt-in is that no one will opt-in to this when using transparent or
gray because it won't make things look any different/better, and the
only places where it does make things look better _do_ work as expected
in Safari anyways.
---------
Co-authored-by: Adam Wathan <4323180+adamwathan@users.noreply.github.com>
Closes#15160
We need to set browser targets for each browser individually to see
vendor prefixes created for each browser.
Exact values are up for discussion, this first pass is taken from
@adamwathan's comments in
https://github.com/tailwindlabs/tailwindcss/issues/15160
---------
Co-authored-by: Adam Wathan <adam.wathan@gmail.com>
Closes#15071
This PR reverts the changes in #15036 which add consistent base styles
for buttons and form controls to Preflight.
While this felt like a good idea (for the reasons explained in that PR),
practically this is just too disruptive of a change for people upgrading
from v3 to v4.
While updating some of our projects to v4 we found ourselves adding
classes to undo styles more often than we expected, and it also felt
inconsistent to have to use a different set of classes to style a link
or a button when we wanted them to look the same.
We also decided it feels a little strange that you could change the
border color of an element without ever specifying that it should have a
border, for example this just feels a little wrong:
```html
<button class="border-blue-500">
```
We also needed to set a default `color-scheme` value for any of this
stuff to work which breaks the ability to use the `color-scheme` meta
tag.
Since this change was a fairly major breaking change and we aren't
feeling much benefit from it, it doesn't feel worth making this change
for v4.
---------
Co-authored-by: Philipp Spiess <hello@philippspiess.com>
This PR updates the default `drop-shadow-*` values to use a single
shadow instead of multiple shadows.
This ensures that the usage with `drop-shadow(var(--drop-shadow-xl))` is
correct because the `drop-shadow(…)` needs to encode a single drop
shadow.
---------
Co-authored-by: Robin Malfait <malfait.robin@gmail.com>
This PR introduces consistent base styles for buttons and form controls
in Tailwind CSS v4.
## Motivation
In v3, form elements lack default styles, which can be
confusing—especially when certain elements, like a text input without a
placeholder or value, are rendered completely invisible on the page.
The goal of this change is to provide reasonable default styles for
buttons, inputs, selects, and textareas that are (mostly) consistent
across all browsers while remaining easy to customize with your own
styles.
This improvement should make Tailwind more accessible for developers new
to the framework and more convenient in scenarios where you need to
quickly create demos (e.g., using Tailwind Play).
## Light and dark mode support
These styles support both light and dark mode, achieved using the
`light-dark()` CSS function. While browser support for this function is
still somewhat limited, Lightning CSS transpiles it to a CSS
variable-based approach that works in older browsers.
For this approach to function correctly, a default `color-scheme` must
be set in your CSS (as explained in [the Lightning CSS
documentation](https://lightningcss.dev/transpilation.html#light-dark()-color-function)).
This PR addresses this requirement by setting the `color-scheme` to
`light` on the `html` element in Preflight.
<img width="1712" alt="image"
src="https://github.com/user-attachments/assets/dba56368-1427-47b3-9419-7c2f6313a944">
<img width="1709" alt="image"
src="https://github.com/user-attachments/assets/3d84fcd2-9606-4626-8e03-164a1dce9018">
## Breaking changes
While we don’t expect these changes to significantly impact v3 users
upgrading to v4, there may be minor differences for those relying on the
simpler v3 styles.
For example, Preflight now applies a `border-radius` to buttons and form
controls. If you weren’t explicitly setting the border radius to `0` in
your project, you’ll need to do so to restore the previous look.
Thankfully, reverting to the v3 styles is straightforward—just add the
following reset to your CSS:
```css
@layer base {
input,
textarea,
select,
button {
border: 0px solid;
border-radius: 0;
padding: 0;
background-color: transparent;
}
}
```
It’s worth noting that this reset doesn't touch the
`::file-selector-button` styles that were added in this PR. This is
because it's not possible to reliably "undo" these styles and restore
the original user-agent styles (which is what was used in v3), as these
are different in each browser. However, these new styles actually match
the defaults in most browsers pretty closely, so hopefully this just
won't be an issue.
## Codemod
This PR includes a codemod that automatically inserts the above
mentioned v3 reset to help avoid breaking changes during the upgrade.
The codemod will insert the following CSS:
```css
/*
In Tailwind CSS v4, basic styles are applied to form elements by default. To
maintain compatibility with v3, the following resets have been added:
*/
@layer base {
input,
textarea,
select,
button {
border: 0px solid;
border-radius: 0;
padding: 0;
background-color: transparent;
}
}
```
## Testing
These changes have been tested across a wide range of browsers,
including Chrome, Safari, Firefox, Edge, and Opera on macOS and Windows,
as well as Safari, Chrome, Firefox, and several lesser-known browsers on
iOS and Android.
However, some quirks still exist in certain mobile browsers, such as iOS
Safari, which adds too much bottom padding below date and time inputs:
<img width="1548" alt="Screenshot 2024-11-20 at 3 57 20 PM"
src="https://github.com/user-attachments/assets/507c7724-ac41-4634-a2b3-61ac4917ebce">
The only reliable way to address these issues is by applying
`appearance: none` to these form controls. However, this felt too
opinionated for Preflight, so we’ve opted to leave such adjustments to
user-land implementations.
---------
Co-authored-by: Jonathan Reinink <jonathan@reinink.ca>
Co-authored-by: Jordan Pittman <jordan@cryptica.me>
Closes#15050
In Tailwind CSS v4 Alpha 31 we changed how we scan template files. This
changes included a new folder-dependency that is emitted for the `base`
directory, so we can listen for new files being added as part of the
postcss dependency.
In our testing, this worked fine with the Next.js integration meaning a
new file in the project root would be picked up by Oxide and we could
update the CSS files accordingly.
This change is now, however, causing an issue. With Next.js 15 **and
with a custom `distDir` configured**, the postcss build, that will write
into the `distDir`, will cause another postcss run to be triggered,
starting an endless loop (regardless of wether or not the `distDir` was
also part of your gitignore list).
This PR now changes the postcss client to not emit the base directory as
a dependency to revert this changes. This does mean that new files and
folders created _directly in the project root_ will require a restart of
the Next.js server again (just like it did in Alpha 31 and before) for
now.
## Test Plan
Next 15 does not seem to run in our current integration test setup (for
some reason the server does not close correctly and it will fail on the
cleanup step), so this change was tested manually:
- First, clone the [templates
repo](https://github.com/philipp-spiess/tailwindcss-playgrounds) I use
for third party frameworks
- Then, do a full build in the parent repo `tailwindcss` via `pnpm
build`
- Now, install the local tarballs in the `tailwindcss-playgrounds` repo
via `pnpm install`
With this setup I have tested changes to a template file (that causes
new utilities to be added) and the CSS file (that will rebuild properly)
across both `pnpm dev` and `pnpm dev --turbo`. Furthermore integration
tests assert it still works in Next 14 like it did before:
https://github.com/user-attachments/assets/b0ccb3dd-d090-4e4c-97c5-74129a2789be
One thing to make sure of is to include the new `distDir` into the
`.gitignore` file as well, otherwise we will scrape it for changes which
inherently causes an endless loop issue again.
---------
Co-authored-by: Adam Wathan <adam.wathan@gmail.com>