This PR injects a `@config "…"` in the CSS file if a JS based config has
been found.
We will try to inject the `@config` in a sensible place:
1. Above the very first `@theme`
2. If that doesn't work, below the last `@import`
3. If that doesn't work, at the top of the file (as a last resort)
When a stylesheet is imported with `@import “…” layer(utilities)` that
means that all classes in that stylesheet and any of its imported
stylesheets become candidates for `@utility` conversion.
Doing this correctly requires us to place `@utility` rules into separate
stylesheets (usually) and replicate the import tree without layers as
`@utility` MUST be root-level. If a file consists of only utilities we
won't create a separate file for it and instead place the `@utility`
rules in the same stylesheet.
Been doing a LOT of pairing with @RobinMalfait on this one but I think
this is finally ready to be looked at
---------
Co-authored-by: Robin Malfait <malfait.robin@gmail.com>
This PR attempts to detect simple postcss setups: These are setups that
do not load dynamic modules and are based off the examples we are
[recommending in our
docs](https://tailwindcss.com/docs/installation/using-postcss). We
detect wether a config is appropriate by having it use the object plugin
config and by not requiring any other modules:
```js
module.exports = {
plugins: {
tailwindcss: {},
autoprefixer: {},
},
}
```
When we find such a config file, we will go over it line-by-line and
attempt to:
- Upgrade `tailwindcss:` to `'@tailwindcss/postcss':`
- Remove `autoprefixer` if used
We then attempt to install and remove the respective npm packages based
on the package manger we detect.
And since we now have logic to upgrade packages, this also makes sure to
install `tailwindcss@next` at the end of a sucessful migration.
---------
Co-authored-by: Robin Malfait <malfait.robin@gmail.com>
This PR adds a codemod that migrates the `@media screen(…)` to the
properly expanded `@media (…)` syntax.
```css
@media screen(md) {
.foo {
color: red;
}
}
```
Will be converted to:
```css
@media (width >= 48rem) {
.foo {
color: red;
}
}
```
If you happen to have custom screens (even complex ones), the screen
will be converted to a custom media query.
```css
@media screen(foo) {
.foo {
color: red;
}
}
```
With a custom `tailwind.config.js` file with a config like this:
```js
module.exports = {
// …
theme: {
screens: {
foo: { min: '100px', max: '123px' },
},
}
}
```
Then the codemod will convert it to:
```css
@media (123px >= width >= 100px) {
.foo {
color: red;
}
}
```
We forgot to pass `options` from `addComponents` to `addUtilities` and
from `matchComponents` to `matchUtilities`.
This didn't affect anything using addComponents but anything that used
`matchComponents` wouldn't have worked 😬
Discovered `matchUtilities(…)` wasn't populating intellisense on v4 when
working on Tailwind Play earlier today. This PR fixes this so plugins
using matchUtilities also have intellisense suggestions.
We currently have three different implementations of the
`resolveThemeValue()` Theme method:
1. The _core_ version which only resolves based on the exact CSS
variable name. This is the v4-only version.
2. A _compat light_ version which attempts to translate a dot-notation
keypath to a CSS variable name.
3. A _full compat_ version which resolves the legacy theme object which
is used whenever a `@plugin` or `@config` is added.
Unfortunately, there are some issues with this approach that we've
encountered when testing the CSS `theme()` function while upgrading
Tailwind Templates to v4 using our upgrading toolkit.
1. The _compat light_ resolver was trying to convert `theme(spacing.1)`
to tuple syntax. Tuples require a nested property access, though, and
instead this should be convert to `theme(--spacing-1)`.
2. We currently only load _full compat_ version if `@plugin` or
`@config` directives are used. It is possible, though, that we need the
full compat mapping in other cases as well. One example we encountered
is `theme(fontWeight.semibold)` which maps to a dictionary in the
default theme that that we do not have an equivalent for in v4
variables.
To fix both issues, we decided to remove the _compat light_ version of
the `theme()` function in favor of adding this behavior to an upgrade
codemod. Instead, the second layer now only decides wether it can use
the _core_ version or wether it needs to upgrade to the _full compat_
version. Since typos would trigger a _hard error_, we do not think this
has unintended performance consequences if someone wants to use the
_core_ version only (they would get an error regardless which they need
to fix in order to continue).
Fixes#14613
Don't crash when trying to read the modification time of a file that
might already be deleted.
Note: This fix is purely theoretical right now as I wasn't able to
reproduce the issue yet.
---------
Co-authored-by: Jordan Pittman <jordan@cryptica.me>
Fixes an issue reported by the React Aria Components team here:
https://github.com/adobe/react-spectrum/issues/7160
Basically `hidden="until-found"` behaves very differently than `hidden`
and doesn't actually use `display: none`, so we don't want to apply the
behavior we apply for the regular `hidden` attribute.
This PR fixes two issues we found when testing the candidate codemodes:
1. Sometimes, core would emit the same candidate twice. This would
result into rewriting a range multiple times, without realizing that
this change might already be applied, causing it to swallow or duplicate
some bytes.
2. The codemods were mutating the `Candidate` object, however since the
`Candidate` parsing is _cached_ in core, it would sometimes return the
same instance. This is an issue especially since we monkey patch the
prefix to `null` when migrating prefixed candidates. This means that a
candidate would be cached that would be _invalid relative to the real
design system_. We fixed this by making sure the mutations would only be
applied to clones of the `Candidate` and I changed the `DesignSystem`
API to return `ReadOnly<T>` versions of these candidates. A better
solution would maybe be to disable the cache at all but this requires
broader changes in Core.
This PR makes the internal `@at-root` API private. Before this PR you
could use `@at-root` in your own CSS, which means that it was part of
the public API. If you (accidentally) used it in variants, you could
generate CSS that was completely broken.
This now introduces a new private `AtRoot` node (similar to the recently
introduced `Context` node) and can only be constructed within the
framework.
In order to properly migrate your Tailwind CSS v3 project to v4, we need
access to the JavaScript configuration object. This was previously only
required for template migrations, but in this PR we're making it so that
this is also a prerequisite of the CSS migrations. This is because some
migrations, like `@apply`, also need to convert candidates that to the
v4 syntax and we need the full config in order to properly validate
them.
In addition to requiring a JS config, we also now attempt to
automatically find the right configuration file inside the current
working directory. This is now matching the behavior of the Tailwind CSS
v3 CLI where it will find the config automatically if it's in the
current directory and called `tailwind.conf.js`.
---------
Co-authored-by: Robin Malfait <malfait.robin@gmail.com>
This PR is a very small improvement. We started pretty printing the
generated CSS (proper indentation) a while ago, so that we can use the
output as-is for intellisense (on hover).
The other day I noticed that when you use `!important` that we attach it
directly to the declaration. Not the end of the world, but this PR
injects a little space to make sure that the `!important` is separated
from the value which makes it a little easier to read and looks more
like what you would write by hand.
Before:
```css
.flex\! {
display: flex!important;
}
```
After:
```css
.flex\! {
display: flex !important;
}
```
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.22 → 1.1.29) · [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>
In v3 it was possible to import `*.js` variants of compat files, e.g.
`tailwindcss/plugin.js` in addition to `tailwindcss/plugin`. We need to
properly map the exports to support this.
This PR fixes an issue where CSS that existed before a layer:
```css
.foo {
color: red;
}
@layer components {
.bar {
color: blue;
}
}
```
Was turned into an `@layer` without a name:
```css
@layer {
.foo {
color: red;
}
}
@utility bar {
color: blue;
}
```
But in this case, it should stay as-is:
```css
.foo {
color: red;
}
@utility bar {
color: blue;
}
```
When a prefix is set in a stylesheet and we found a candidate that is
equal to the prefix we would crash:
```css
@import "tailwindcss" prefix(tomato);
```
```js
console.log("tomato")
```
This PR fixes this case by ensuring that we have something that looks
like a variant before considering a prefix.
This PR allows modifying utility output by wrapping all utility
declarations in a custom selector or marking all utility declarations as
`!important`. This is the v4 equivalent to the `important` option in the
`tailwind.config.js` file.
## Mark all utility declarations as `!important`
To add `!important` to all utility declarations, you add an `important`
flag after the `@import` statement for `tailwindcss` or
`tailwindcss/utilities`:
```css
/** Importing `tailwindcss` */
@import "tailwindcss" important;
/** Importing the utilities directly */
@import "tailwindcss/utilities" important;
```
Example utility output:
```css
.mx-auto {
margin-left: auto !important;
margin-right: auto !important;
}
.text-center {
text-align: center !important;
}
```
This is equivalent to adding `important: true` to the
`tailwind.config.js` file — which is still supported for backwards
compatibility.
## Wrap all utility declarations in a custom selector
To nest all utilities in an `#app` selector you add `selector(#app)`
flag after the `@import` statement for `tailwindcss` or
`tailwindcss/utilities`:
```css
/** Importing `tailwindcss` */
@import "tailwindcss" selector(#app);
/** Importing the utilities directly */
@import "tailwindcss/utilities" selector(#app);
```
Example utility output:
```css
.mx-auto {
#app & {
margin-left: auto;
margin-right: auto;
}
}
.text-center {
#app & {
text-align: center;
}
}
```
This is equivalent to adding `important: "#app"` to the
`tailwind.config.js` file — which is still supported for backwards
compatibility.
**This _does not_ bring back support for the `respectImportant` flag in
`addUtilities` / `matchUtilities`.**
This PR improves the performance of the `@tailwindcss/postcss` plugin.
Before this change we created 2 compiler instances instead of a single
one. On a project where a `tailwindcss.config.ts` file is used, this
means that the timings look like this:
```
[@tailwindcss/postcss] Setup compiler: 137.525ms
⋮
[@tailwindcss/postcss] Setup compiler: 43.95ms
```
This means that with this small change, we can easily shave of ~50ms for
initial PostCSS builds.
---------
Co-authored-by: Philipp Spiess <hello@philippspiess.com>
Co-authored-by: Jordan Pittman <jordan@cryptica.me>
This PR extracts all _candidate migrations_ from the existing _template
migrations_ and reuses these in the `@apply` CSS migration. Seems like
this _JustWorks✨_.
---------
Co-authored-by: Adam Wathan <adam.wathan@gmail.com>
Part-of #14558
After handling `@import` of stylesheets in core, we can no longer gate
out features based on finding a specific sequence in the input CSS, as
this string will not contain contents from other stylesheets.
So, consider the following input CSS:
```css
@import "tailwindcsss";
@import "./styles.css";
```
We can't opt-out of the traversal to search for `@apply` based on it
because it, of course, does not contain the contents of `./styles.css`
yet.
---------
Co-authored-by: Adam Wathan <adam.wathan@gmail.com>
One of the breaking changes of v4 is the [inversion of variant order
application](https://github.com/tailwindlabs/tailwindcss/pull/13478). In
v3, variants are applied "inside-out".
For example a candidate like `*:first:underline` would produce the
following CSS in v3:
```css
.\*\:first\:underline:first-child > * {
text-decoration-line: underline;
}
```
To get the same behavior in v4, you would need to invert the candidate
order to `first:*:underline`. This would generate the following CSS in
v4:
```css
:where(.first\:\*\:underline:first-child > *) {
text-decoration-line: underline;
}
```
## The Migration
The most naive approach would be to invert the variants for every
candidate with at least two variants. This, however, runs into one issue
and some unexpected inconsistencies. I have identified the following
areas:
1. Some pseudo class variants _must appear at the end of the selector_.
v3 was patching over this by doing some manual reordering in for these
variants. For example, in v3, both of these variants create the same
output CSS: `hover:before:underline` and `before:hover:underline`. In v4
we simplified this system though and no longer generate the same output
in both cases. Instead, you'd always want to write
`hover:before:underline`, ensuring that these variants will appear at
the end.
For an exact list of which variants these affect, take a look [at this
diff](https://github.com/tailwindlabs/tailwindcss/pull/13478/files#diff-7779a0eebf6b980dd3abd63b39729b3023cf9a31c91594f5a25ea020b066e1c0L228-L246).
2. The `dark` variant and other at-rule variants are usually written
before other variants. This is more of a recommendation to make it
easier to read candidates rather than a difference in behavior as
`@media` queries are hoisted by the engine. For this reason, both of
these variants are _correct_ yet in real applications we prefer the
first one: `lg:hover:underline`, `hover:lg:underline`.
To avoid shuffling these rules across all candidates during the
migration, we bucket `dark` and other at-rule variants into a special
bucket that will not have their order changed (since people wrote stacks
like `sm:max-lg:` before and we want to keep them as-is) and appear
before all other variants.
3. For some variant stacks, the order does not matter. E.g.:
`focus:hover:underline` and `hover:focus:underline` will be the same. We
don't want to needlessly shuffle their order if we have to.
With these considerations, the migration now works as follows:
- If there is less then two variants, we do not need to migrate the
candidate
- If _every_ variant in the stack is an order-independent variant, we do
not need to migrate the candidate
- _Note that this is currently hardcoded to only support `&:hover` and
`&:focus`._
- Otherwise, we loop over the candidates and put them into three
buckets:
- `mediaVariants` hold variants that only contribute `@media` rules
_and_ the `dark` variant.
- `pseudoElementVariants` hold variants that _must appear at the end of
the selector_. This is based on the allow list from v3/early v4.
- `regularVariants` contains the rest.
- We now compute if any of the variants inside `regularVariants` is
order dependent.
- With this list of variants, we now construct the new order of variants
as:
```ts
[
...atRuleVariants,
...(anyRegularVariantOrderDependent ? regularVariants.reverse() :
regularVariants),
...pseudoElementVariants,
]
```
---------
Co-authored-by: Adam Wathan <adam.wathan@gmail.com>
Replaces #11271 — the merge conflicts are killing me and it's way easier
to just do it again (added you as a co-author though @lukewarlow so
you're still credited!)
This PR adds the following new utilities for the `color-scheme`
property:
| Class | CSS |
| ------------------- | -------------------------- |
| `scheme-normal` | `color-scheme: normal` |
| `scheme-dark` | `color-scheme: dark` |
| `scheme-light` | `color-scheme: light` |
| `scheme-light-dark` | `color-scheme: light dark` |
| `scheme-only-dark` | `color-scheme: dark only` |
| `scheme-only-light` | `color-scheme: light only` |
Went with `scheme-*` for the utilities because there are currently no
other CSS properties with the word `scheme` in them and
`scheme-light-dark` is going to be a common value which is three words
already even with the shortened property name.
I considered setting `color-scheme: light dark` by default as part of
Preflight for this PR but decided against it, at least for this PR. I
think that could still be a useful default but we should think about it
a bit more because if you're building a light-mode-only site it'll force
you to do some extra work.
---------
Co-authored-by: Adam Wathan <4323180+adamwathan@users.noreply.github.com>
Co-authored-by: Luke Warlow <lwarlow@igalia.com>
I noticed our prefix tests were missing an explicit test for `@import
"tailwindcss" prefix(tw)` so this PR tweaks an existing test to test
that case.
Also noticed that `prefix.test.ts` was in the `compat` folder even
though this is a v4 feature, so moved it out to the root.
---------
Co-authored-by: Adam Wathan <4323180+adamwathan@users.noreply.github.com>
This PR adds a new migration that can migrate Tailwind CSS v3 style
prefixes into Tailwind CSS v4.
The migration is split into three separate pieces of work:
1. Firstly, we need to read the full JavaScript config to get the _old_
prefix option. This is necessary because in v4, we will not allow things
like custom-separators for the prefix. From this option we will then try
and compute a new prefix (in 90% of the cases this is going to just
remove the trailing `-` but it can also work in more complex cases).
2. Then we migrate all Candidates. The important thing here is that we
need to operate on the raw candidate string because by relying on
`parseCandidate` (which we do for all other migrations) would not work,
as the candidates are not valid in v4 syntax. More on that in a bit.
3. Lastly we also make sure to update the CSS config to include the new
prefix. This is done by prepending the prefix option like so:
```css
@import "tailwindcss" prefix(tw);
```
### Migrating candidates
The main difference between v3 prefixes and v4 prefixes is that in v3,
the prefix was _part of the utility_ where as in v4 it is _always in
front of the CSS class.
So, for example, this candidate in v3:
```
hover:-tw-mr-4
```
Would be converted to the following in v4:
```
tw:hover:-mr-4
```
Since the first example _won't parse as a valid Candidate in v4, as the
`tw-mr` utility does not exist, we have to operate on the raw candidate
string first. To do this I created a fork of the `parseCandidate`
function _without any validation of utilities or variants_. This is used
to identify part of the candidate that is the `base` and then ensuring
the `base` starts with the old prefix. We then remove this to create an
"unprefixed" candidate that we validate against a version of the
DesignSystem _with no prefixes configured_. If the variant is valid this
way, we can then print it again with the `DesignSystem` that has the new
prefix to get the migrated version.
Since we set up the `DesignSystem` to include the new prefix, we can
also be certain that migrations that happen afterwards would still
disqualify candidates that aren't valid according to the new prefix
policy. This does mean we need to have the prefix fixup be the first
step in our pipeline.
One interesting bit is that in v3, arbitrary properties did not require
prefixes where as in v4 they do. So the following candidate:
```
[color:red]
```
Will be converted to:
```
tw:[color:red]
```
I noticed some more unexpected values being passed through as _bare
values_: Decimal places with zero.
These should not generate CSS but currently does:
- `from-25.%`
- `from-25.0%`
- `from-25.00%`
- etc.
In v4, we're [removing automatic var
injection](https://github.com/tailwindlabs/tailwindcss/pull/13657)
(please refer to this PR for more detail as to why).
Automatic var injection made it so that if you have a candidate like
`bg-[--my-color]`, v3 would automatically wrap the content of the
arbitrary section with a `var(…)`, resulting in the same as typing
`bg-[var(--my-color)]`.
This PR adds codemods that go over various arbitrary fields and does the
`var(…)` injection for you. To be precise, we will add `var(…)` to:
- Modifiers, e.g.: `bg-red-500/[var(--my-opacity)]`
- Variants, e.g.: `supports-[var(--test)]:flex`
- Arbitrary candidates, e.g.: `[color:var(--my-color)]`
- Arbitrary values for functional candidates, e.g.:
`bg-[var(--my-color)]`
---------
Co-authored-by: Robin Malfait <malfait.robin@gmail.com>
This PR adds support for the `blocklist` config option when using a JS
config file in v4. You can now block certain classes from being
generated at all. This is useful in cases where scanning files sees
things that look like classes but are actually not used. For example, in
paragraphs in a markdown file:
```js
// tailwind.config.js
export default {
blocklist: ['bg-red-500'],
}
```
```html
<!-- index.html -->
<div class="bg-red-500 text-black/75"></div>
```
Output:
```css
.text-black/75 {
color: rgba(0, 0, 0, 0.75);
}
```
This PR exposes when using the the `DEBUG` environment variable. This
follows the `DEBUG` conventions where:
- `DEBUG=1`
- `DEBUG=true`
- `DEBUG=*`
- `DEBUG=tailwindcss`
Will enable the debug information, but when using:
- `DEBUG=0`
- `DEBUG=false`
- `DEBUG=-tailwindcss`
It will not.
This currently only exposes some timings related to:
1. Scanning for candidates
2. Building the CSS
3. Optimizing the CSS
We can implement a more advanced version of this where we also expose
more fine grained information such as the files we scanned, the amount
of candidates we found and so on. But I believe that this will be enough
to start triaging performance related issues.
This PR inserts the `@import` in a more sensible location when running
codemods.
The idea is that we replace `@tailwind base; @tailwind components;
@tailwind utilities;` with the much simple `@import "tailwindcss";`. We
did this by adding the `@import` to the top of the file.
While this is correct, this means that the diff might not be as clear.
For example, if you have a situation where you have a license comment:
```css
/**! My license comment */
@tailwind base;
@tailwind components;
@tailwind utilities;
```
This resulted in:
```css
@import "tailwindcss";
/**! My license comment */
```
While it is not wrong, it feels weird that this behaves like this. In
this commit we make sure that it is injected in-place (the first
`@tailwind` at-rule we find) and fixup the position if we can't inject
it in-place.
The above example results in this:
```css
/**! My license comment */
@import "tailwindcss";
```
However, there are scenario's where you can't replace the `@tailwind`
directives directly. E.g.:
```css
/**! My license comment */
html {
color: red;
}
@tailwind base;
@tailwind components;
@tailwind utilities;
```
If we replace the `@tailwind` directives in-place, it would look like
this:
```css
/**! My license comment */
html {
color: red;
}
@import "tailwindcss";
```
But this is invalid CSS, because you can't have CSS above an `@import`
at-rule. There are some exceptions like:
- `@charset`
- `@import`
- `@layer foo, bar;` (just the order, without a body)
- comments
In this scenario, we inject the import in the nearest place where it is
allowed to. In this case:
```css
/**! My license comment */
@import "tailwindcss";
@layer base {
html {
color: red;
}
}
```
Additionally, we will wrap the existing CSS in an `@layer` of the first
Tailwind directive we saw. In this case an `@layer base`. This ensures
that utilities still win from the default styles.
Also note that the (license) comment is allowed to exist before the
`@import`, therefore we do not put the `@import` above it. This also
means that the diff doesn't touch the license header at all, which makes
the diffs cleaner and easier to reason about.
---------
Co-authored-by: Philipp Spiess <hello@philippspiess.com>
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?
#### ✳️ @types/bun (1.1.8 → 1.1.10) ·
[Repo](https://github.com/DefinitelyTyped/DefinitelyTyped)
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 lands a quick interface update for template migration with some
lessons learned form our existing migrations. Specifically, this version
attempts to:
- Allow migrations to access the raw candidate. This way we can migrate
candidates that _would not parse as valid in v4_. This will help us
migrate prefixes in candidates from v3 to v4.
- There is no more awkward "return null" if nothing has changed. The
return `null` was necessary because we relied on mutating the Variant
and since parsing/printing could remove some information, it was not
easy to find out wether a candidate needed to be migrated at all. With a
string though, we can do this cheaply by returning the `rawCandidate`.
- We previously asserted that if `parseCandidate` returns more than one
candidate, we only picked the first one. This behavior is now moved into
the migrations where we have more context. For now though, we still do
not need to worry about this since in all cases, these duplicate
candidates would serialize to the same `Candidate`. It is helpful if you
only want to run a migration on a specific type of candidate (e.g. if
there's a `static` one and a more generic `functional` one).
- We need access to the `DesignSystem` inside migrations now to be able
to `parseCandidate`s.
Opening this up as a separate PR since it can take some time to iron out
the edge cases for the individual codemod PRs and I don't want to be
rebasing all the time.
## Before
```ts
type Migration = (candidate: Candidate) => Candidate | null
```
## After
```ts
type Migration = (designSystem: DesignSystem, rawCandidate: string) => string
```
In v4, we're making room for more gradient primitives with the addition
of [gradient and conic gradient
utilities](https://github.com/tailwindlabs/tailwindcss/pull/14467). To
make this clearer, we are renaming all v3 `bg-gradient-*` utilities to
`bg-linear-*` to make it clear that these refer to linear gradients.
This PR adds a migration that will automatically update the class names
based on this migration.
Fixes#14521
When using the CLI to read files from `stdin` like this:
```bash
npx tailwindcss --input=- -o bar.css < foo.css
```
We need to set the `base` path to be the current working directory
(`process.cwd()`). However, `cwd()` already _is_ a directory and calling
`dirname()` on it did go to the parent directory _which might not have
the `tailwindcss` dependency installed.
This PR fixes an issue where a CSS rule with a selector that contains
multiple selectors lost everything but the last selector.
While testing the `npx @tailwindcss/upgrade` codemods on real world
projects, I noticed that we lost one of the selectors in the
`docker/docs` repository.
```diff
diff --git a/assets/css/toc.css b/assets/css/toc.css
index 91ff92d7cd..3b2432e913 100644
--- a/assets/css/toc.css
+++ b/assets/css/toc.css
@@ -2,7 +2,7 @@
#TableOfContents {
.toc a {
@apply block max-w-full truncate py-1 pl-2 hover:font-medium hover:no-underline;
- &[aria-current="true"],
+
&:hover {
@apply border-l-2 border-l-gray-light bg-gradient-to-r from-gray-light-100 font-medium text-black dark:border-l-gray-dark dark:from-gray-dark-200 dark:text-white;
}
```
This PR fixes the issue by not overriding the `node.selector` internally
with the last selector we handled. Instead, we let the selector parser
handle it entirely.
This PR adds the initial setup and a first codemod for the template
migrations. These are a new set of migrations that operate on files
defined in the Tailwind v3 config as part of the `content` option (so
your HTML, JavaScript, TSX files etc.).
The migration for this is integrated in the new `@tailwindcss/upgrade`
package and will require pointing the migration to an input JavaScript
config file, like this:
```
npx @tailwindcss/upgrade --config tailwind.config.js
```
The idea of template migrations is to apply breaking changes from the v3
to v4 migration within your template files.
## Migrating !important syntax
The first migration that I’m adding with this PR is to ensure we use the
v4 important syntax that has the exclamation mark at the end of the
utility.
For example, this:
```html
<div class="!flex sm:!block"></div>
```
Will now turn into:
```html
<div class="flex! sm:block!"></div>
```
## Architecture considerations
Implementation wise, we make use of Oxide to scan the content files fast
and efficiently. By relying on the same scanner als Tailwind v4, we
guarantee that all candidates that are part of the v4 output will have
gone through a migration.
Migrations itself operate on the abstract `Candidate` type, similar to
the type we use in the v4 codebase. It will parse the candidate into its
parts so they can easily be introspected/modified. Migrations are typed
as:
```ts
type TemplateMigration = (candidate: Candidate) => Candidate | null
```
`null` should be returned if the `Candidate` does not need a migration.
We currently use the v4 `parseCandidate` function to get an abstract
definition of the candidate rule that we can operate on. _This will
likely need to change in the future as we need to fork `parseCandidate`
for v3 specific syntax_.
Additionally, we're inlining a `printCandidate` function that can
stringify the abstract `Candidate` type. It is not guaranteed that this
is an identity function since some information can be lost during the
parse step. This is not a problem though, because migrations will only
run selectively and if none of the selectors trigger, the candidates are
not updated. h/t to @RobinMalfait for providing the printer.
So the overall flow of a migration looks like this:
- Scan the config file for `content` files
- Use Oxide to extract a list of candidate and their positions from
these `content` files
- Run a few migrations that operate on the `Candidate` abstract type.
- Print the updated `Candidate` back into the original `content` file.
---------
Co-authored-by: Robin Malfait <malfait.robin@gmail.com>
Co-authored-by: Jordan Pittman <jordan@cryptica.me>
This PR adds support for requiring a custom prefix on utility classes.
Prefixes work a bit differently in v4 than they did in v3:
- They look like a custom variant: `tw:bg-white`
- It is always first in a utility — even before other variants:
`tw:hover:bg-white`
- It is required on **all** utility classes — even arbitrary properties:
`tw:[color:red]`
- Prefixes also apply to generated CSS variables which will be separated
by a dash: `--tw-color-white: #fff;`
- Only alpha (a-z) characters are allowed in a prefix — so no `#tw#` or
`__` or similar prefixes are allowed
To configure a prefix you can use add `prefix(tw)` to your theme or when
importing Tailwind CSS like so:
```css
/* when importing `tailwindcss` */
@import 'tailwindcss' prefix(tw);
/* when importing the theme separately */
@import 'tailwindcss/theme' prefix(tw);
/* or when using an entirely custom theme */
@theme prefix(tw) {
--color-white: #fff;
--breakpoint-sm: 640px;
/* … */
}
```
This will configure Tailwind CSS to require a prefix on all utility
classes when used in HTML:
```html
<div class="tw:bg-white tw:p-4">
This will have a white background and 4 units of padding.
</div>
<div class="bg-white p-4">
This will not because the prefix is missing.
</div>
```
and when used in CSS via `@apply`:
```css
.my-class {
@apply tw:bg-white tw:p-4;
}
```
Additionally, the prefix will be added to the generated CSS variables.
You **do not** need to prefix the variables in the `@theme` block
yourself — Tailwind CSS handles this automatically.
```css
:root {
--tw-color-white: #fff;
--tw-breakpoint-sm: 640px;
}
```
A prefix is not necessary when using the `theme(…)` function in your CSS
or JS given that plugins will not know what the current prefix is and
must work with or without a prefix:
```css
.my-class {
color: theme(--color-white);
}
```
However, because the variables themselves are prefixed when outputting
the CSS, you **do** need to prefix the variables when using `var(…)` in
your CSS:
```css
.my-class {
color: var(--tw-color-white);
}
```
If you want to customize the prefix itself change `tw` to something
else:
```css
/* my:underline, my:hover:bg-red-500, etc… */
@import 'tailwindcss' prefix(my);
```
---------
Co-authored-by: Philipp Spiess <hello@philippspiess.com>
When CSS exists between two tailwind directives, then the CSS will be
wrapped in an `@layer` to ensure it all ends up in the correct location
in the final CSS file.
However, if the only thing between two tailwind directives is a comment,
then the comment will also be wrapped in an `@layer` directive.
E.g.:
```css
@tailwind base;
/* This is a comment */
@tailwind components;
/* This is another comment */
@tailwind utilities;
```
Results in:
```css
@import "tailwindcss";
@layer base {
/* This is a comment */
}
@layer components {
/* This is another comment */
}
```
In this case, the layers don't matter, so this can be simplified to:
```css
@import "tailwindcss";
/* This is a comment */
/* This is another comment */
```
This PR fixes an issue where some `@import` at-rules had an empty
`layer()` attached at the end of the `@import` string.
We should only add that if a Tailwind directive or Tailwind import such
as `@tailwind base` or `@import "tailwindcss/base"` preceded the current
`@import` at-rule. If there was no Tailwind directive, the `lastLayer`
will be empty and we don't need to attach it to the `@import` string.
This PR improves the missing layers codemod where everything after the
last Tailwind directive can stay as-is without wrapping it in a `@layer`
directive.
The `@layer` at-rules are only important for CSS that exists between
Tailwind directives.
E.g.:
```css
@tailwind base;
html {}
@tailwind components;
.btn {}
@tailwind utilities;
.foo {}
.bar {}
```
Was transformed into:
```css
@import "tailwindcss";
@layer base {
html {}
}
@layer components {
.btn {}
}
@layer utilities {
.foo {}
.bar {}
}
```
But the last `@layer utilities` is already in the correct spot, so we
can simplify this to just this instead:
```css
@import "tailwindcss";
@layer base {
html {}
}
@layer components {
.btn {}
}
.foo {}
.bar {}
```
This PR adds a codemod that ensures that some parts of your stylesheet
are wrapped in an `@layer`.
This is a follow-up PR of #14411, in that PR we migrate `@tailwind`
directives to imports.
As a quick summary, that will turn this:
```css
@tailwind base;
@tailwind components;
@tailwind utilities;
```
Into:
```css
@import 'tailwindcss';
```
But there are a few issues with that _if_ we have additional CSS on the
page. For example let's imagine we had this:
```css
@tailwind base;
body {
background-color: red;
}
@tailwind components;
.btn {}
@tailwind utilities;
```
This will now be turned into:
```css
@import 'tailwindcss';
body {
background-color: red;
}
.btn {}
```
But in v4 we use real layers, in v3 we used to replace the directive
with the result of that layer. This means that now the `body` and `.btn`
styles are in the incorrect spot.
To solve this, we have to wrap them in a layer. The `body` should go in
an `@layer base`, and the `.btn` should be in an `@layer components` to
make sure it's in the same spot as it was before.
That's what this PR does, the original input will now be turned into:
```css
@import 'tailwindcss';
@layer base {
body {
background-color: red;
}
}
@layer components {
.btn {
}
}
```
There are a few internal refactors going on as well, but those are less
important.