Early in v4 development we decided to give all form controls a
transparent background, but in v3 we only did this for button elements.
This PR reverts that decision to make things consistent with v3, as
we've noticed this is something that tends to break for people when
upgrading from v3 to v4.
The default background color of form elements is the [`Field` system
color](https://developer.mozilla.org/en-US/docs/Web/CSS/system-color#field)
which automatically adapts to light and dark modes if you don't touch
it, so it feels reasonable to keep this as the default. Changing it just
makes upgrading harder and doesn't really make anything easier for
anyone else.
---------
Co-authored-by: Adam Wathan <4323180+adamwathan@users.noreply.github.com>
When using an opacity modifier such as `bg-black/[var(--opacity)]`, then
this was translated to:
```css
.bg-black\/\[var\(--opacity\)\] {
background-color: color-mix( in oklch, var(--color-black, #000) calc(var(--opacity) * 100%), transp
}
```
The issue is that this part: `calc(var(--opacity) * 100%)` is invalid
_if_ the `var(--opacity)` already contains a percentage value. See:
https://play.tailwindcss.com/xz0t
This is because this eventually resolves to `calc(20% * 100%)` and `20%
100%` is invalid in CSS.
In Catalyst we use variables like that _with_ the `%` included, which
means that v4 doesn't work as expected when using this.
A variable with a `%` included is probably the better value to support
compared to the the unit less one. This also allows you to define your
variables using `@property` as a proper `<percentage>` type.
Unfortunately the `var(--opacity)` is a value that can change at
runtime, so we don't know the type at compile time.
In the future we might be able to use `first-valid(…)` (see:
https://drafts.csswg.org/css-values-5/#f and generate both versions at
the same time.
---------
Co-authored-by: Adam Wathan <adam.wathan@gmail.com>
We noticed an issue that the `theme()` function wourld not properly
parse in CSS if you split the argument list over multiple lines. This is
fixed by treating `\n` and `\t` the same as space:
```css
.custom-font {
font-family: theme(
fontFamily.unknown,
Helvetica Neue,
Helvetica,
sans-serif
);
}
```
## Test plan
Added tests, but also tried it in the Vite example:
<img width="1995" alt="Screenshot 2024-11-08 at 13 46 09"
src="https://github.com/user-attachments/assets/f9bf94b0-3f9b-4334-8911-9190987e2df5">
This PR fixes an issue where utilities like `px` would read the
`--spacing` variable and use its value as the utility value, similar to
how `shadow` reads `--shadow` by default. That doesn't make sense for
these utilities since `--spacing` is reserved as a special multiplier
variable.
---------
Co-authored-by: Adam Wathan <4323180+adamwathan@users.noreply.github.com>
This ensures our glob hoisting mechanism (see #14896) works on Windows
when performing an upgrade.
---------
Co-authored-by: Jordan Pittman <jordan@cryptica.me>
This PR adds migrations for the recent changes to the `--spacing` scale
done in #12263.
There are a few steps that we do to ensure we have the best upgrade
experience:
- If you are overwriting the `spacing` theme with custom values, we now
check if the new values are multiplies of the default spacing scale.
When they are, we can safely remove the overwrite.
- If you are extending the `spacing` theme, we will unset the default
`--spacing` scale and only use the values you provided.
- Any `theme()` function calls are replaced with `calc(var(--spacing) *
multiplier)` unless the values are extending the default scale.
One caveat here is for `theme()` key which can not be replaced with
`var()` (e.g. in `@media` attribute positions). These will not be able
to be replaced with `calc()` either so the following needs to stay
unmigrated:
```css
@media (max-width: theme(spacing.96)) {
.foo {
color: red;
}
}
```
## Test plan
We are mainly testing two scenarios: The JS config _extends_ the
`spacing` namespace and the JS config _overwrites_ the `spacing`
namespace. For both cases we have added an integration test each to
ensure this works as expected. The test contains a mixture of keys (some
of it matching the default multiples, some don't, some have different
scales, and some use non-numeric identifiers). In addition to asserting
on the created CSS `@theme`, we also ensure that `theme()` calls are
properly replaced.
---------
Co-authored-by: Adam Wathan <adam.wathan@gmail.com>
Co-authored-by: Adam Wathan <4323180+adamwathan@users.noreply.github.com>
This PR updates all of the `--font-size-*` variables to `--text-*`
instead to closer match the utility names.
```diff
@theme {
- --font-size-xs: 0.75rem;
- --font-size-xs--line-height: 1rem;
- --font-size-sm: 0.875rem;
- --font-size-sm--line-height: 1.25rem;
- --font-size-base: 1rem;
- --font-size-base--line-height: 1.5rem;
- --font-size-lg: 1.125rem;
- --font-size-lg--line-height: 1.75rem;
- --font-size-xl: 1.25rem;
- --font-size-xl--line-height: 1.75rem;
/* ... */
+ --text-xs: 0.75rem;
+ --text-xs--line-height: 1rem;
+ --text-sm: 0.875rem;
+ --text-sm--line-height: 1.25rem;
+ --text-base: 1rem;
+ --text-base--line-height: 1.5rem;
+ --text-lg: 1.125rem;
+ --text-lg--line-height: 1.75rem;
+ --text-xl: 1.25rem;
+ --text-xl--line-height: 1.75rem;
/* ... */
}
```
This is part of a bigger set of changes where we're renaming other theme
variables as well with the same goals, since many existing theme
variables like `--shadow-*` and `--radius-*` are already not using the
explicit CSS property name.
---------
Co-authored-by: Adam Wathan <4323180+adamwathan@users.noreply.github.com>
Co-authored-by: Philipp Spiess <hello@philippspiess.com>
Co-authored-by: Jordan Pittman <jordan@cryptica.me>
This PR adds a new `**` variant to target any level of children.
This is very similar to the `*` variant, the big difference is that:
- `*` applies to direct children only
- `**` applies to any level of children
Thought of this because of all the recent work we did around globs. So a
good analogy for this is glob syntax where you have the exact same
difference. `*.html` vs `**/*.html`.
This PR fixes an issue where unsetting `--font-*` would unset
`--font-weight-*` and `--font-size-*`.
```css
@theme {
--font-weight-bold: bold;
--font-size-sm: 14px;
--font-sans: sans-serif;
--font-serif: serif;
}
@theme {
--font-*: initial;
--font-body: Inter;
}
```
Up until now this was sort of intended/desired behavior but with recent
changes there are now more overlapping theme keys (`--inset-*` and
`--inset-shadow-*` as well for example), and we don't want to make it
impossible to unset _just_ the default `font-family` values.
This PR also simplifies how we were handling making sure that the
`inset-*` utility ignored `--inset-shadow-*` variables since it's all
really the same problem.
This does mean we need to maintain a list of known theme keys so we know
when there is a conflict between two keys, which is kind of unfortunate
because up until now this was a totally dynamic thing. End users can
still add whatever custom stuff they want under `@theme` but we don't
really know about those namespaces since we're maintaining a static list
so we can't resolve conflicts there. I'm confident there are ways we
could solve this if it actually becomes a problem, so content to push
forward without solving it right now and just deal with it if/when it
actually arises, because it just might not.
---------
Co-authored-by: Adam Wathan <4323180+adamwathan@users.noreply.github.com>
Fixes: #14839Fixes: #14796
This PR fixes an issue in the Vite extension where we previously only
ran a small list of allow-listed plugins for the second stage transform
in the build step. This caused some CSS features to unexpectedly not
work in production builds (one such example is Vue's `:deep(...)`
selector).
To fix this, I changed the allow listed plugins that we do want to run
to a block list to filter out some plugins we know we don't want to run
(e.g. the Tailwind Vite plugin for example or some built-in Vite plugins
that are not necessary).
## Test plan
This PR adds a new integration test suite to test interop with a custom
Vite transformer that looks like this:
```js
{
name: 'recolor',
transform(code, id) {
if (id.includes('.css')) {
return code.replace(/red/g, 'blue')
}
},
}
```
I also validated that this does indeed fix the Vue `:deep(...)` selector
related issue that we were seeing by copying the repro of #14839 into
our playground:

You can see in the screenshot above that the `:deep()` selector
overwrites the scoped styles as expected in both the dev mode and the
prod build (screenshotted).
Furthermore I reproduced the issue reported in
https://github.com/tailwindlabs/tailwindcss/issues/14796 and was able to
confirm that in a production build, the styling works as expected:
<img width="517" alt="Screenshot 2024-11-06 at 14 26 50"
src="https://github.com/user-attachments/assets/ade6fe38-be0d-4bd0-9a9a-67b6fec05ae0">
Lastly, I created a repository out of the biggest known-to-me Vite
projects: [Astro, Nuxt, Remix, SolidStart, and
SvelteKit](https://github.com/philipp-spiess/tailwind-playgrounds) and
verified that both dev and prod builds show no issue and the candidate
list is properly appended in each case.
---------
Co-authored-by: Jordan Pittman <jordan@cryptica.me>
Co-authored-by: Adam Wathan <adam.wathan@gmail.com>
Fixes#14784
This is an alternative to #14850 in which we actually perform url
rewriting / rebasing ourselves. We ported a large portion of the
URL-rewriting code from Vite (with attribution) to use here with some
minor modifications. We've added test cases for the url rewriting so
verifying individual cases is easy. We also wrote integration tests for
Vite that use PostCSS and Lightning CSS that verify that files are found
and inlined or relocated/renamed as necessary.
We also did some manual testing in the Playground to verify that this
works as expected across several CSS files and directories which you can
see a screenshot from here:
<img width="1344" alt="Screenshot 2024-11-05 at 10 25 16"
src="https://github.com/user-attachments/assets/ff0b3ac8-cdc9-4e26-af79-36396a5b77b9">
---------
Co-authored-by: Philipp Spiess <hello@philippspiess.com>
This PR fixes an issue where globs in you `content` configuration escape
the current "root" of the project.
This can happen if you have a folder, and you need to look up in the
tree (e.g.: when looking at another package in a monorepo, or in case of
a Laravel project where you want to look at mail templates).
This applies a similar strategy we already implement on the Rust side.
1. Expand braces in the globs
2. Move static parts of the `pattern` to the `base` of the glob entry
object
---
Given a project setup like this:
```
.
├── admin
│ ├── my-tailwind.config.ts
│ └── src
│ ├── abc.jpg
│ ├── index.html
│ ├── index.js
│ └── styles
│ └── input.css
├── dashboard
│ ├── src
│ │ ├── index.html
│ │ ├── index.js
│ │ ├── input.css
│ │ └── pickaday.css
│ └── tailwind.config.ts
├── package-lock.json
├── package.json
├── postcss.config.js
└── unrelated
└── index.html
7 directories, 14 files
```
If you then have this config:
```ts
// admin/my-tailwind.config.ts
export default {
content: {
relative: true,
files: ['./src/**/*.html', '../dashboard/src/**/*.html'],
// ^^ this is the important part, which escapes
// the current root of the project.
},
theme: {
extend: {
colors: {
primary: 'red',
},
},
},
}
```
Then before this change, running the command looks like this:
<img width="1760" alt="image"
src="https://github.com/user-attachments/assets/60e2dfc7-3751-4432-80e3-8b4b8f1083d4">
After this change, running the command looks like this:
<img width="1452" alt="image"
src="https://github.com/user-attachments/assets/5c47182c-119c-4732-a253-2dace7086049">
---------
Co-authored-by: Philipp Spiess <hello@philippspiess.com>
During the migration process, a lot of changes to the CSS file happen.
Some parts are converted, some parts are deleted and some new CSS is
added.
To make sure we are generating a sensible and good looking CSS file, we
will sort the final CSS and pretty print it.
The order we came up with looks like this:
```css
/* Imports */
@import "tailwindcss";
@import "../other.css";
/* Configuration */
@config "../path/to/tailwindcss.config.js";
@plugin "my-plugin-1";
@plugin "my-plugin-2";
@source "./foo/**/*.ts";
@source "./bar/**/*.ts";
@variant foo {}
@variant bar {}
@theme {}
/* Border compatibility CSS */
@layer base {}
/* Utilities */
@utility foo {}
@utility bar {}
/* Rest of your own CSS if any */
```
---------
Co-authored-by: Philipp Spiess <hello@philippspiess.com>
This PR renames all of the `--width-*` variables to `--container-*` to
better communicate the purpose of these tokens as layout container
sizes. These are the values that were historically stored under
`maxWidth` in the v3 and earlier eras, and were also re-used by the
container queries plugin.
The name `--container-*` feels like a better match alongside the
`--breakpoint-*` namespace and since these both serve that same sort of
purpose it makes sense to me that the name should be optimized for
feeling "right" in that context.
I like that this also sort of advertises Tailwind's support for
container queries directly in the CSS variables themselves, and helps
people understand what these are really intended to be used for.
---------
Co-authored-by: Adam Wathan <4323180+adamwathan@users.noreply.github.com>
This PR renames the `--transition-timing-function-*` theme variables to
`--ease-*` to more closely match the utility names and be a bit more
terse in general.
```diff
@theme {
- --transition-timing-function-in: cubic-bezier(0.4, 0, 1, 1);
- --transition-timing-function-out: cubic-bezier(0, 0, 0.2, 1);
- --transition-timing-function-in-out: cubic-bezier(0.4, 0, 0.2, 1);
+ --ease-in: cubic-bezier(0.4, 0, 1, 1);
+ --ease-out: cubic-bezier(0, 0, 0.2, 1);
+ --ease-in-out: cubic-bezier(0.4, 0, 0.2, 1);
}
```
This is part of a bigger set of changes where we're renaming other theme
variables as well with the same goals, since many existing theme
variables like `--shadow-*` and `--radius-*` are already not using the
explicit CSS property name.
---------
Co-authored-by: Adam Wathan <4323180+adamwathan@users.noreply.github.com>
This PR renames the `--font-family-*` theme variables to `--font-*` to
more closely match the utility names and be a bit more terse in general.
```diff
@theme {
- --font-family-sans: ui-sans-serif, system-ui, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol', 'Noto Color Emoji';
- --font-family-serif: ui-serif, Georgia, Cambria, 'Times New Roman', Times, serif;
- --font-family-mono: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, 'Liberation Mono', 'Courier New', monospace;
+ --font-sans: ui-sans-serif, system-ui, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol', 'Noto Color Emoji';
+ --font-serif: ui-serif, Georgia, Cambria, 'Times New Roman', Times, serif;
+ --font-mono: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, 'Liberation Mono', 'Courier New', monospace;
}
```
This is part of a bigger set of changes where we're renaming other theme
variables as well with the same goals, since many existing theme
variables like `--shadow-*` and `--radius-*` are already not using the
explicit CSS property name.
---------
Co-authored-by: Adam Wathan <4323180+adamwathan@users.noreply.github.com>
This PR improves the generated CSS by running it through Lightning CSS
twice.Right now Lightning CSS merges adjacent at-rules and at the end
flattens the nesting. This means that after the nesting is flattened,
the at-rules that are adjacent and could be merged together will not be
merged.
This PR improves our output by running Lightning CSS twice on the
generated CSS which will make sure to merge adjacent at-rules after the
nesting is flattened.
Note: in the diff output you'll notice that some properties are
duplicated. These need some fixes in Lightning CSS itself but they don't
break anything for us right now.
Related PR in Lightning CSS for the double `-webkit-backdrop-filter` can
be found here: https://github.com/parcel-bundler/lightningcss/pull/850
---------
Co-authored-by: Philipp Spiess <hello@philippspiess.com>
This PR adds a migration for migrating the changes we implemented in
https://github.com/tailwindlabs/tailwindcss/pull/14849
This is the migration we perform:
| Old | New |
| ----------------- | ------------------ |
| `shadow` | `shadow-sm` |
| `shadow-sm` | `shadow-xs` |
| `shadow-xs` | `shadow-2xs` |
| `inset-shadow` | `inset-shadow-sm` |
| `inset-shadow-sm` | `inset-shadow-xs` |
| `inset-shadow-xs` | `inset-shadow-2xs` |
| `drop-shadow` | `drop-shadow-sm` |
| `drop-shadow-sm` | `drop-shadow-xs` |
| `rounded` | `rounded-sm` |
| `rounded-sm` | `rounded-xs` |
| `blur` | `blur-sm` |
| `blur-sm` | `blur-xs` |
Also added an integration test to ensure that `shadow` is properly
migrated to `shadow-sm`, and doesn't get migrated to `shadow-xs`
(because `shadow-sm` is migrated to `shadow-xs`).
This PR fixes an issue where some special characters (with an actual
meaning CSS) were used inside of the `url(…)` function, would result in
incorrectly parsed CSS.
For example, when we encounter a `{`, then we would start a new "block"
for nesting purposes. If we encounter an `}`, then the block would end.
If we encounter a `;`, then that would be the end of a declaration.
All of that is true, unless we are in a `url(…)` function. In that case,
we should ignore all of those characters and treat them as part of the
URL.
This is only an issue because:
1. We are allowed to use these characters in URLs.
2. We can write an url inside `url(…)` without quotes. With quotes, this
would not be an issue.
---------
Co-authored-by: Philipp Spiess <hello@philippspiess.com>
This PR removes all of the static `font-weight` utilities that were
previously hard-coded into the framework in favor of deriving those
utilities from the `--font-weight-*` theme values instead.
Biggest motivation for this is giving people a way to explicitly disable
font-weight utilities they don't want to use in their project, which
previously wasn't possible.
---------
Co-authored-by: Adam Wathan <4323180+adamwathan@users.noreply.github.com>
This PR changes how we render `var(...)` calls for theme values,
removing the fallback values we were previously including.
```diff
.text-white {
- color: var(--color-white, #fff);
+ color: var(--color-white);
}
```
We previously included the fallbacks only so you could see the value in
dev tools but this feels like a bad reason to bloat the CSS. I'd rather
just convince the Chrome team to surface this stuff better in dev tools
in the first place.
---------
Co-authored-by: Adam Wathan <4323180+adamwathan@users.noreply.github.com>
This PR replaces the default spacing scale (`--spacing-*`) with a
generative system based on a default spacing _unit_.
Instead of the default theme containing values like `--spacing-4`,
`--spacing-6`, `--spacing-8`, etc., instead we just define a single
`--spacing` value:
```css
@theme {
--spacing: 0.25rem;
}
```
Utilities like `px-4` are derived from this unit by multiplying it by
the value in the utility (4 in this case):
```css
.px-4 {
padding-inline: calc(var(--spacing) * 4);
}
```
The biggest consequence of this change is that every value is available
now, rather than just the explicitly configured values.
This means utilities like `px-42` will work now, whereas prior to this
PR only `px-40` and `px-44` were valid utilities. I personally found it
very difficult to know which values actually existed at the higher end
of the scale without IntelliSense, and in practice even when working
with a skilled designer like [Steve](https://x.com/steveschoger) who
helped design Tailwind's default spacing scale, I'd very often need to
break out of it to implement a design, and trying to round to a value
that was in the scale made the design worse, not better.
This PR allows you to use any whole number, as well as decimal numbers
that are multiples of `0.25` to ensure classes like `px-1.5` continue to
work. While this means you can now technically do things like
`pt-97.25`, I think the presence of the fractional value will be enough
of a signal to developers that they are doing something a little
unusual, and they can use their judgment as to whether they are making
the right decision or not.
I'll update this PR with a lot more detail when I have a chance, as
there are a few other things to explain like:
- Unifying all of the values for
width/min-width/max-width/height/min-height/max-height utilities
- Deriving numeric line-height values from the spacing multiplier
instead of a separate line-height scale
- Using `--spacing: initial` to disable the multiplier
- How you can still use an explicit spacing scale and ignore this change
- How we plan to use IntelliSense to surface a more curated set of
spacing values even if smaller increments work when you type them
explicitly
---------
Co-authored-by: Adam Wathan <4323180+adamwathan@users.noreply.github.com>
This PR removes `--transition-timing-function-linear` from the default
theme in favor of a static `ease-linear` utility. Doesn't make sense for
this to be a design token since `linear` can only mean `linear`.
This is consistent with how we handle basically every other similar case
in the framework.
---------
Co-authored-by: Adam Wathan <4323180+adamwathan@users.noreply.github.com>
This PR reworks the default `--shadow-*` and `--inset-shadow-*` scales
to remove the bare `shadow` and `inset-shadow` utilities, and ensure
every shadow has an explicit size as part of the utility name.
Here's a complete list of changes:
| v3 | v4 Alpha | Proposed |
| ----------------- | ----------------- | ------------------ |
| _N/A_ | `shadow-xs` | `shadow-2xs` |
| `shadow-sm` | `shadow-sm` | `shadow-xs` |
| `shadow` | `shadow` | `shadow-sm` |
| `shadow-md` | `shadow-md` | `shadow-md` |
| `shadow-lg` | `shadow-lg` | `shadow-lg` |
| `shadow-xl` | `shadow-xl` | `shadow-xl` |
| _N/A_ | `inset-shadow-xs` | `inset-shadow-2xs` |
| _N/A_ | `inset-shadow-sm` | `inset-shadow-xs` |
| `shadow-inner` | `inset-shadow` | `inset-shadow-sm` |
The motivation for this change is just to make the scale more
predictable — it's never been intuitive to me that `shadow` sits in
between `shadow-sm` and `shadow-md`.
This PR doesn't remove the ability to create classes like `shadow` and
`inset-shadow` by adding bare `--shadow` and `--inset-shadow` theme
variables, but does remove them from the default theme.
## Impact
We'll include a codemod for this in our upgrade tool to automate this
change for people upgrading from v3 to v4, but this is still sort of an
annoying breaking change admittedly and will make lots of educational
resources, example components, and LLM tools out of date for v4 😕 At the
same time I don't want to feel like we can never correct regrettable
legacy decisions just to preserve backward compatibility.
We made a similar change like this when we went from the v0.x color
palette to the v1.x color palette changing names like `bg-red` to
`bg-red-500` and that proved to definitely be the right decision long
term, so want to rip the band-aid off here too if we can.
Planning to make the same change for `rounded`, `drop-shadow`, and
`blur` as well — maybe in separate PRs but maybe just all in this one as
well since I don't think we want to do one and not all.
_Update_: I've also made the same changes to the `--radius-*`,
`--drop-shadow-*`, and `--blur-*` scales now, effectively removed the
`rounded`, `drop-shadow`, and `blur` classes by default, and changing
the meaning `rounded-sm`, `drop-shadow-sm`, and `blur-sm`.
We'll put together a codemod to handle this stuff in a separate PR.
---------
Co-authored-by: Adam Wathan <4323180+adamwathan@users.noreply.github.com>
When migrating a project from Tailwind CSS v3 to Tailwind CSS v4, then
we started the migration process in the following order:
1. Migrate the JS/TS config file
2. Migrate the source files (found via the `content` option)
3. Migrate the CSS files
However, if you have a setup where you have multiple CSS root files
(e.g.: `frontend` and `admin` are separated), then that typically means
that you have an `@config` directive in your CSS files. These point to
the Tailwind CSS config file.
This PR changes the migration order to do the following:
1. Build a tree of all the CSS files
2. For each `@config` directive, migrate the JS/TS config file
3. For each JS/TS config file, migrate the source files
If a CSS file does not contain any `@config` directives, then we start
by filling in the `@config` directive with the default Tailwind CSS
config file (if found, or the one passed in). If no default config file
or passed in config file can be found, then we will error out (just like
we do now)
---------
Co-authored-by: Adam Wathan <adam.wathan@gmail.com>
This PR fixes a issue where utilities like `inset-x-*`, `left-*`,
`top-*`, etc. mistakenly pull values from the `--inset-ring-*` and
`--inset-shadow-*` theme namespaces.
For example, the class `left-shadow-sm` currently generates this CSS:
```css
.left-shadow-sm {
left: var(
--inset-shadow-sm,
inset 0 1px 1px rgb(0 0 0 / 0.05)
);
}
```
This happens because the `--inset-ring-*` and `--inset-shadow-*`
namespaces collide with the `--inset-*` namespace.
We were already handling this manually for just the `inset-*` utilities
but didn't realize we needed to handle it for every related utility, so
this PR fixes that.
This also fixes an issue where IntelliSense would suggest classes like
`inset-x-shadow-sm` when they shouldn't actually exist.
To do this we've created this new concept of `ignoredThemeKeys` in the
relevant APIs to make sure these are filtered out at the source.
---------
Co-authored-by: Adam Wathan <4323180+adamwathan@users.noreply.github.com>
This PR removes `--drop-shadow-none` from the default theme which
shouldn't ever have been there since we handle all `*-none` utilities as
static/permanent utilities in the framework now.
I've added `drop-shadow-none` as an explicit static utility, and also
slightly improved test coverage for `getClassList` around drop shadows
while touching this part of the code.
---------
Co-authored-by: Adam Wathan <4323180+adamwathan@users.noreply.github.com>
Right now our variant sorting is sensitive to the authoring order of
classes or the order in which we scan files because we weren't comparing
variant values when sorting.
This PR addresses this by:
- "default" values in variants appear first
- Then any named values
- Then any arbitrary values
- Finally, compare the values themselves when all else is equal
---------
Co-authored-by: Robin Malfait <malfait.robin@gmail.com>
Co-authored-by: Adam Wathan <4323180+adamwathan@users.noreply.github.com>
Co-authored-by: Adam Wathan <adam.wathan@gmail.com>
This PR is an improvement/fix by making sure that whitespace around the
`,` separator is removed when printing arbitrary values.
Before:
```diff
- <div class="grid-cols-[min(50%,theme(spacing.80))_auto]"></div>
+ <div class="grid-cols-[min(50%,_var(--spacing-80))_auto]"></div>
```
After:
```diff
- <div class="grid-cols-[min(50%,theme(spacing.80))_auto]"></div>
+ <div class="grid-cols-[min(50%,var(--spacing-80))_auto]"></div>
```
---------
Co-authored-by: Jordan Pittman <jordan@cryptica.me>
This PR fixes an issue where a `@source` crashes when the path
eventually resolves to a path ending in `..`.
We have to make sure that we canonicalize the path to make sure that we
are working with the real directory.
---------
Co-authored-by: Jordan Pittman <jordan@cryptica.me>
This PR improves the PostCSS migrations to make sure that we install
`@tailwindcss/postcss` in the same bucket as `tailwindcss`.
If `tailwindcss` exists in the `dependencies` bucket, we install
`@tailwindcss/postcss` in the same bucket. If `tailwindcss` exists in
the `devDependencies` bucket, we install `@tailwindcss/postcss` in the
same bucket.
This also contains an internal refactor that normalizes the package
manager to make sure we can install a package to the correct bucket
depending on the package manager.
---------
Co-authored-by: Adam Wathan <adam.wathan@gmail.com>
Here is everything you need to know about this upgrade. Please take a
good look at what changed and the test results before merging this pull
request.
### What changed?
#### ✳️ postcss-selector-parser (6.1.2 → 7.0.0) ·
[Repo](https://github.com/postcss/postcss-selector-parser) ·
[Changelog](https://github.com/postcss/postcss-selector-parser/blob/master/CHANGELOG.md)
<details>
<summary>Release Notes</summary>
<h4><a
href="https://github.com/postcss/postcss-selector-parser/releases/tag/v7.0.0">7.0.0</a></h4>
<blockquote><h1 dir="auto">7.0.0</h1>
<ul dir="auto">
<li>Feat: make insertions during iteration safe (major)</li>
</ul></blockquote>
<p><em>Does any of this look wrong? <a
href="https://depfu.com/packages/npm/postcss-selector-parser/feedback">Please
let us know.</a></em></p>
</details>
<details>
<summary>Commits</summary>
<p><a
href="1b1e9c3bc1...6158750aab">See
the full diff on Github</a>. The new version differs by 2 commits:</p>
<ul>
<li><a
href="6158750aab"><code>chore(release):
7.0.0</code></a></li>
<li><a
href="4fa6e860a1"><code>feat!:
make insertions during iteration safe (#295)</code></a></li>
</ul>
</details>
---

[Depfu](https://depfu.com) will automatically keep this PR
conflict-free, as long as you don't add any commits to this branch
yourself. You can also trigger a rebase manually by commenting with
`@depfu rebase`.
<details><summary>All Depfu comment commands</summary>
<blockquote><dl>
<dt>@depfu rebase</dt><dd>Rebases against your default branch and
redoes this update</dd>
<dt>@depfu recreate</dt><dd>Recreates this PR, overwriting any edits
that you've made to it</dd>
<dt>@depfu merge</dt><dd>Merges this PR once your tests are passing and
conflicts are resolved</dd>
<dt>@depfu cancel merge</dt><dd>Cancels automatic merging of this
PR</dd>
<dt>@depfu close</dt><dd>Closes this PR and deletes the branch</dd>
<dt>@depfu reopen</dt><dd>Restores the branch and reopens this PR (if
it's closed)</dd>
<dt>@depfu pause</dt><dd>Ignores all future updates for this dependency
and closes this PR</dd>
<dt>@depfu pause [minor|major]</dt><dd>Ignores all future minor/major
updates for this dependency and closes this PR</dd>
<dt>@depfu resume</dt><dd>Future versions of this dependency will
create PRs again (leaves this PR as is)</dd>
</dl></blockquote>
</details>
Co-authored-by: depfu[bot] <23717796+depfu[bot]@users.noreply.github.com>
<!--depfu-start-->
> 👉 **This PR is queued up to get rebased by Depfu**
<!--depfu-end-->
Here is everything you need to know about this update. Please take a
good look at what changed and the test results before merging this pull
request.
### What changed?
#### ✳️ bun (1.1.29 → 1.1.33) · [Repo](https://github.com/oven-sh/bun)
Sorry, we couldn't find anything useful about this release.
---

[Depfu](https://depfu.com) will automatically keep this PR
conflict-free, as long as you don't add any commits to this branch
yourself. You can also trigger a rebase manually by commenting with
`@depfu rebase`.
<details><summary>All Depfu comment commands</summary>
<blockquote><dl>
<dt>@depfu rebase</dt><dd>Rebases against your default branch and
redoes this update</dd>
<dt>@depfu recreate</dt><dd>Recreates this PR, overwriting any edits
that you've made to it</dd>
<dt>@depfu merge</dt><dd>Merges this PR once your tests are passing and
conflicts are resolved</dd>
<dt>@depfu cancel merge</dt><dd>Cancels automatic merging of this
PR</dd>
<dt>@depfu close</dt><dd>Closes this PR and deletes the branch</dd>
<dt>@depfu reopen</dt><dd>Restores the branch and reopens this PR (if
it's closed)</dd>
<dt>@depfu pause</dt><dd>Ignores all future updates for this dependency
and closes this PR</dd>
<dt>@depfu pause [minor|major]</dt><dd>Ignores all future minor/major
updates for this dependency and closes this PR</dd>
<dt>@depfu resume</dt><dd>Future versions of this dependency will
create PRs again (leaves this PR as is)</dd>
</dl></blockquote>
</details>
Co-authored-by: depfu[bot] <23717796+depfu[bot]@users.noreply.github.com>
This PR introduces a new `source(…)` argument and improves on the
existing `@source`. The goal of this PR is to make the automatic source
detection configurable, let's dig in.
By default, we will perform automatic source detection starting at the
current working directory. Auto source detection will find plain text
files (no binaries, images, ...) and will ignore git-ignored files.
If you want to start from a different directory, you can use the new
`source(…)` next to the `@import "tailwindcss/utilities"
layer(utilities) source(…)`.
E.g.:
```css
/* ./src/styles/index.css */
@import 'tailwindcss/utilities' layer(utilities) source('../../');
```
Most people won't split their source files, and will just use the simple
`@import "tailwindcss";`, because of this reason, you can use
`source(…)` on the import as well:
E.g.:
```css
/* ./src/styles/index.css */
@import 'tailwindcss' source('../../');
```
Sometimes, you want to rely on auto source detection, but also want to
look in another directory for source files. In this case, yuo can use
the `@source` directive:
```css
/* ./src/index.css */
@import 'tailwindcss';
/* Look for `blade.php` files in `../resources/views` */
@source '../resources/views/**/*.blade.php';
```
However, you don't need to specify the extension, instead you can just
point the directory and all the same automatic source detection rules
will apply.
```css
/* ./src/index.css */
@import 'tailwindcss';
@source '../resources/views';
```
If, for whatever reason, you want to disable the default source
detection feature entirely, and only want to rely on very specific glob
patterns you define, then you can disable it via `source(none)`.
```css
/* Completely disable the default auto source detection */
@import 'tailwindcss' source(none);
/* Only look at .blade.php files, nothing else */
@source "../resources/views/**/*.blade.php";
```
Note: even with `source(none)`, if your `@source` points to a directory,
then auto source detection will still be performed in that directory. If
you don't want that, then you can simply add explicit files in the globs
as seen in the previous example.
```css
/* Completely disable the default auto source detection */
@import 'tailwindcss' source(none);
/* Run auto source detection in `../resources/views` */
@source "../resources/views";
```
---------
Co-authored-by: Jordan Pittman <jordan@cryptica.me>
Co-authored-by: Adam Wathan <4323180+adamwathan@users.noreply.github.com>
This PR introduces an internal refactor where we introduce the `AtRule`
CSS Node in our AST.
The motivation for this is that in a lot of places we need to
differentiate between a `Rule` and an `AtRule`. We often do this with
code that looks like this:
```ts
rule.selector[0] === '@' && rule.selector.startsWith('@media')
```
Another issue we have is that we often need to check for `'@media '`
including the space, because we don't want to match `@mediafoobar` if
somebody has this in their CSS. Alternatively, if you CSS is minified
then it could be that you have a rule that looks like
`@media(width>=100px)`, in this case we _also_ have to check for
`@media(`.
Here is a snippet of code that we have in our codebase:
```ts
// Find at-rules rules
if (node.kind === 'rule') {
if (
node.selector[0] === '@' &&
(node.selector.startsWith('@media ') ||
node.selector.startsWith('@media(') ||
node.selector.startsWith('@custom-media ') ||
node.selector.startsWith('@custom-media(') ||
node.selector.startsWith('@container ') ||
node.selector.startsWith('@container(') ||
node.selector.startsWith('@supports ') ||
node.selector.startsWith('@supports(')) &&
node.selector.includes(THEME_FUNCTION_INVOCATION)
) {
node.selector = substituteFunctionsInValue(node.selector, resolveThemeValue)
}
}
```
Which will now be replaced with a much simpler version:
```ts
// Find at-rules rules
if (node.kind === 'at-rule') {
if (
(node.name === '@media' ||
node.name === '@custom-media' ||
node.name === '@container' ||
node.name === '@supports') &&
node.params.includes(THEME_FUNCTION_INVOCATION)
) {
node.params = substituteFunctionsInValue(node.params, resolveThemeValue)
}
}
```
Checking for all the cases from the first snippet is not the end of the
world, but it is error prone. It's easy to miss a case.
A direct comparison is also faster than comparing via the
`startsWith(…)` function.
---
Note: this is only a refactor without changing other code _unless_ it
was required to make the tests pass. The tests themselves are all
passing and none of them changed (because the behavior should be the
same).
The one exception is the tests where we check the parsed AST, which now
includes `at-rule` nodes instead of `rule` nodes when we have an
at-rule.
This PR adds a migration to bump the `prettier-plugin-tailwindcss`
version to the latest version when upgrading your project. This is to
ensure that the plugin is compatible with the latest version of Tailwind
CSS.
Note: we will only do this _if_ you already used the
`prettier-plugin-tailwindcss` plugin in your project.
This PR updates all of our x/y named utilities (like `px-*`, `my-*`,
`inset-y-*`, `scroll-px-*`, etc.) to use logical properties like
`padding-inline` instead of separate `padding-left` and `padding-right`
properties.
We held off on this originally for a while because `inline` doesn't
really mean _horizontal_ like the "x" in `px-*` implies, but I think in
practice this change is fine — I'm comfortable with "x" meaning "in the
inline direction" and "y" meaning "in the block direction" in Tailwind.
This is technically a breaking change if anyone was depending on the
fact that `px-*` for instance was always explicitly setting
`padding-left` and `padding-right` even when building something in a
vertical writing mode, but I kinda doubt there's a single real project
on the internet that will actually be affected, so not too worried about
it.
If someone _really_ wants to set `padding-left` and `padding-right` they
can always use `pl-4 pr-4` instead of `px-4`.
Nice thing about this change is it produces quite a bit less CSS.
To test this change, I re-generated all of the snapshots and made sure
none of the generated utilities changed position or anything in the
output (initially they did before I updated `property-order.ts` to add
some missing properties).
I also created a little demo locally in the Vite playground to test
things manually and make sure I didn't make any obvious typos or
anything that could slip through the snapshots:
<img width="1223" alt="image"
src="https://github.com/user-attachments/assets/0e9854ba-2b5b-4c8c-87b6-6eb7b7da84f2">
<details>
<summary>Show code for playground demo</summary>
```jsx
import React from 'react'
export function App() {
return (
<div className="p-12 gap-10 grid grid-cols-2 items-start">
<div className="grid grid-cols-1 gap-10 justify-start">
<div className="space-y-6">
<p className="font-semibold mb-6">Border Width</p>
<div className="border-x w-48 h-12 flex items-center justify-center">border-x</div>
<div className="border-y w-48 h-12 flex items-center justify-center">border-y</div>
</div>
<div className="space-y-6">
<p className="font-semibold mb-6">Border Color</p>
<div className="border-2 border-x-red-500 w-48 h-12 flex items-center justify-center">
border-x-red-500
</div>
<div className="border-2 border-y-red-500 w-48 h-12 flex items-center justify-center">
border-y-red-500
</div>
</div>
<div className="space-y-6">
<p className="font-semibold mb-6">Padding</p>
<div>
<div className="px-8 bg-yellow-300 inline-flex items-center justify-center">px-8</div>
</div>
<div>
<div className="py-8 bg-yellow-300 inline-flex items-center justify-center">py-8</div>
</div>
</div>
</div>
<div className="grid grid-cols-1 gap-10 justify-start">
<div className="space-y-6">
<p className="font-semibold mb-6">Margin</p>
<div>
<div className="bg-red-400 inline-flex">
<div className="mx-8 bg-yellow-300 inline-flex items-center justify-center">mx-8</div>
</div>
</div>
<div>
<div className="bg-red-400 inline-flex">
<div className="my-8 bg-yellow-300 inline-flex items-center justify-center">my-8</div>
</div>
</div>
</div>
<div className="space-y-6">
<p className="font-semibold mb-6">Inset</p>
<div className="relative bg-red-400 w-48 h-48">
<div className="inset-x-8 absolute bg-yellow-300 inline-flex items-center justify-center">
inset-x-8
</div>
</div>
<div className="relative bg-red-400 w-48 h-48">
<div className="inset-y-8 absolute bg-yellow-300 inline-flex items-center justify-center">
inset-y-8
</div>
</div>
</div>
</div>
</div>
)
}
```
</details>
I didn't manually test the scroll padding or scroll margin utilities
because they are more annoying to set up, but I probably should.
---------
Co-authored-by: Adam Wathan <4323180+adamwathan@users.noreply.github.com>
This PR is a continuation of #14783 to handle the feedback on that PR.
1. Update the test to be more realistic
2. Updated the comment
---------
Co-authored-by: Adam Wathan <4323180+adamwathan@users.noreply.github.com>
This PR implements some changes to the way we sort typography utilities,
inspired by #14715.
Prior to this PR, utilities like `text-balance`, `break-words`, and
`text-center` were sorted very early, even before things like border
utilities:
```html
<div class="text-balance break-words border-2 border-blue-500 text-center indent-5 text-2xl font-medium capitalize leading-6 tracking-tight text-red-500 underline"></div>
```
This PR changes the sort order to co-locate these with other typography
utilities which feels a lot more natural:
```html
<div class="border-2 border-blue-500 text-center indent-5 text-2xl leading-6 font-medium tracking-tight text-balance break-words text-red-500 capitalize underline"></div>
```
I've also made some small adjustments to how other typography properties
are sorted based on pairing with @reinink and just deciding what felt
the most intuitive to us and matched the order we'd likely type things
in manually.
To test this change I temporarily added a new test to `sort.test.ts` to
make sure the classes were sorted in the expected order:
```js
[
// Input
'text-red-500 text-center capitalize text-2xl break-words text-balance underline font-medium tracking-tight leading-6 indent-5',
// Expected
'text-center indent-5 text-2xl leading-6 font-medium tracking-tight text-balance break-words text-red-500 capitalize underline',
],
```
Didn't keep the test around because there's no real logic to test here
(it just matches the order in the `property-order.ts` file) and we don't
have any other tests like this.
I've also made some minor unrelated changes here like deleting legacy
properties from `property-order.ts` that are never used, and fixing a
typo where we wrote `work-break` instead of `word-break`.
---------
Co-authored-by: Adam Wathan <4323180+adamwathan@users.noreply.github.com>
I've tweaked the changelog with suggestions from @adamwathan to improve
clarity around what the actual changes are.
I also renamed `compoundWith` back to `compound` — I felt that it made
sense at the time but keeping the old name definitely feels better the
more I think about it.
This PR fixes an issue where `layer(…)` next to imports were removed
where they shouldn't have been removed.
The issue exists if _any_ of the `@import` nodes in a file contains
`@utility`, if that's the case then we removed the `layer(…)` next to
_all_ `@import` nodes.
Before we were checking if the current sheet contained `@utility` or in
any of its children (sub-`@import` nodes).
This fixes that by looping over the `@import` nodes in the current
sheet, and looking for the `@utility` in the associated/imported file.
This way we update each node individually.
Test plan:
---
Added a dedicated integration test to make sure all codemods together
result in the correct result. Input:
96e8908378/integrations/upgrade/index.test.ts (L2076-L2108)
Output:
96e8908378/integrations/upgrade/index.test.ts (L2116-L2126)