6155 Commits

Author SHA1 Message Date
Philipp Spiess
eec1bf2b84
Fix --theme(…) function when legacy JS plugins are used (#17458)
Closes #17346

This PR fixes an issue that caused the `--theme(…)` function to behave
differently after a legacy JS plugin or config was configured. The issue
was that the compatibility layer would patch the theme value resolver to
always inline the value. This, however, is only expected to happen if
the path does not look like a CSS variable in which case this legacy
code path should not be run.

To fix this, I'm now keeping a reference to the regular theme resolution
function and call into it if the path starts with `--`.

## Test plan

- Tested with the repro in #17346 by adding pnpm overrides and confirmed
that this fixes the issue
- Added a unit test to the `--theme(…)` resolution tests
2025-03-31 13:06:28 +02:00
Jordan Pittman
c32b6082a1
Add object-{top,bottom}-{left,right} utilities (#17437)
These match the new `mask-*` and updated `bg-*` utilities.

This is the same as #17378 but for `object-position`.

| Deprecated utility    | New utility           |
| --------------------- | --------------------- |
| `object-left-top`     | `object-top-left`     |
| `object-right-top`    | `object-top-right`    |
| `object-left-bottom`  | `object-bottom-left`  |
| `object-right-bottom` | `object-bottom-right` |
2025-03-28 15:58:17 -04:00
Jordan Pittman
f77226652a
Add new mask-image utilities for Tailwind CSS v4.1 (#17134) 2025-03-28 13:24:40 -04:00
Jordan Pittman
1a68b99368
Add support for “intensity” modifiers on box and text shadows (#17398)
This PR adds support for utilities like:
- `text-shadow-lg/25`

It uses relative color syntax to replace the alpha value of the shadow
from your theme.

When combined with a colors:
- `text-shadow-lg/25 text-shadow-red-500`
- `text-shadow-lg/25 text-shadow-red-500/75`

The alpha values are **multiplied** resulting in a shadow with the color
specified in `--color-red-500` and alpha values of 25% and 18.75%
respectively.
2025-03-28 13:16:00 -04:00
Philipp Spiess
5e255deb0e
Add text-shadow-* utilities (#17389)
This PR adds new `text-shadow-*` utilities and default values courtesy
of @danhollick's.

Usage is similar to the normal `shadow-*` utilities, for example:

```html
<h1 class="text-center text-7xl tracking-tight text-white text-shadow-xl">
  Some fancy <br />
  headline
</h1>
```

Since this PR also adds first-class support for the `--text-shadow`
theme namespace, it also means it resolves #17047.

## Test plan

- Copied @danhollick's [demo
playground](https://play.tailwindcss.com/lbA3Y6VY8u) to the `vite` setup
and ran a production build to ensure it looks correct:
https://tailwind-text-shadows-preview-2kdnjb32b.vercel.app/

---------

Co-authored-by: Jordan Pittman <jordan@cryptica.me>
Co-authored-by: Robin Malfait <malfait.robin@gmail.com>
2025-03-28 13:06:56 -04:00
Robin Malfait
2af7c57983
Extract used CSS variables from .css files (#17433)
This PR fixes an issue where CSS variables could be used in CSS modules,
but where never emitted in your final CSS.

Some backstory, when Tailwind CSS v4 came out, we _always_ emitted all
CSS variables whether they were used or not.

Later, we added an optimization where we only emit the CSS variables
that were actually used. The definition of "used" in this case is:

1. Used in your CSS  file(s) — (we check the final CSS AST for this)
2. Used _somewhere_ in any of your source files (e.g.: a JavaScript file
accessing a variable)

The issue this PR tries to solve is with the very first point. If you
are using CSS modules, then every CSS file is processed separately. This
is not a choice Tailwind CSS made, but how other build tooling works
(like Vite for example).

To prevent emitting all of Tailwind's Preflight reset and all utilities
per CSS file, you can use the `@reference` directive instead of
repeating `@import "tailwindcss";`. This is explained here:
https://tailwindcss.com/docs/compatibility#explicit-context-sharing

But now we are just _referencing_ them, not emitting them. And since the
CSS module is not connected in any way to the main `index.css` file that
contains the `@import "tailwindcss";` directive, we don't even see the
CSS variables while processing the `index.css` file. (or wherever your
main CSS file is)

This is where point 2 from above comes in. This is a situation where we
rely on the extractor to find the used CSS variables so we can
internally mark them as used.

To finally get to the point of this PR, the extractor only scans
`.html`, `.js`, ... files but not `.css` files. So all the CSS variables
used inside of CSS modules will not be generated.

This PR changes that behavior to also scan `.css` files. But _only_ for
CSS variables (not any other type of class candidate). This is
important, otherwise all your custom `@utility foo {}` definitions would
always mark `foo` as a used class and include it in the CSS which is not
always the case.

On top extracting CSS variables, we will also make sure that the CSS
variables we find are in usage positions (e.g.: `var(--color-red-500)`)
and not in definition positions (e.g.: `--color-red-500: #ff0000;`).
This is important because we only want to emit the variables that are
actually used in the final CSS output.

One future improvement not implemented here, is that technically we will
also extract CSS variables that might not be used if defined in a
`@utility`.

```css
@utility never-used {
  color: var(--color-red-500); /* --color-red-500 will be emitted, even if it might not be used */
}
```

Fixes: #16904
Fixes: #17429

# Test plan

1. Added a test where CSS variables are defined in `.css` files (and
ignored)
2. Added a test where CSS variables are used in `.css` files (and
included)

Testing on the reproduction defined in #16904, the `.module.css` file
contains a reference to `var(--color-hot-pink)`, but generating a build
shows that the variable definition is not available:

<img width="1630" alt="image"
src="https://github.com/user-attachments/assets/a0d5c37e-6813-4cd5-a677-6c356b5a73d4"
/>

When you run the build again with the changes from this PR, then we _do_
see the definition of the `--color-hot-pink` in the root CSS file:
<img width="2876" alt="image"
src="https://github.com/user-attachments/assets/beab7c11-a31b-4ea4-8235-4849a8e92859"
/>
2025-03-28 17:53:15 +01:00
Jordan Pittman
3412a9623d
Add bg-{position,size}-* utilities (#17432)
This PR adds `bg-{position,size}-*` utilities that support arbitrary
values. This exist as the new preferred version of something like this:

```
bg-[120px_120px]
```

Is it size or position (hint: it's the 2nd one).

To override it you'd have to provide a data type:
```
bg-[size:120px_120px]
```


Now you can be more explicit and have better intellisense by writing
these:
```
bg-position-[120px_120px]
bg-size-[120px_120px]
```
2025-03-28 16:40:57 +00:00
Jordan Pittman
ab868c6098
Improve arbitrary value validation when parsing candidates (#17361)
Fixes #17357

This affects the CDN and Play

Now candidates like these no longer parse and emit CSS:
- `[--foo:1rem;--bar:2rem]`
- `[&{color:red}]:flex`
- `data-[a]{color:red}foo[a]:flex`
2025-03-28 12:38:57 -04:00
Jordan Pittman
1b6230f54f
Rework scripting variants (#17431)
This replaces the `scripting`, `scripting-none`, and `scripting-initial`
variants with one `noscript` variant that matches the name of the HTML
`<noscript>` element. The previous `scripting` can then be represented
as `not-noscript` e.g. `not-noscript:flex`.
2025-03-28 12:28:20 -04:00
Philipp Spiess
9cceeaa87f Fix PR number on change log 2025-03-28 17:14:50 +01:00
Robin Malfait
601f369374
Extract special @("@")md:… syntax in Razor files (#17427)
This PR fixes an extraction issue in Razor files where `@@md:bg-red-500`
can't always be extracted properly. We already convert `@@md:bg-red-500`
to ` @md:bg-red-500` but in certain situations Razor will emit the
double `@@` to the DOM.

A workaround in Razor land would be to write `@("@")md:bg-red-500`
instead. See: https://github.com/dotnet/aspnetcore/issues/38595 But then
we don't extract the `@md:bg-red-500` properly anymore.

This is where this PR comes in, essentially we will pre process the
Razor contents and apply the following replacement internally:

```diff
- @("@")md:bg-red-500
+      @md:bg-red-500
```
Notice that the `)` looks like it's replaced with `@`. This will have a
small side effect later when we get to the testing part.

But this way we properly see the `@md:bg-red-500` class during class
extraction.

> [!WARNING]
> There is technically a bug here because of the replacement with `@`,
because if you now run the `npx @tailwindcss/upgrade@latest` tool, then
we would replace `)md:bg-red-500` if changes are required, not the
`@("@")md:bg-red-500` part. We can try to fix that in this PR but it
seems unlikely that we will actually run into this issue realistically
speaking. I think fixing the actual extraction here is much more
important than the upgrade tooling that could fail _if_ we ever have to
migrate `@md:…` to something else.

Fixes: #17424

## Test plan

1. Added a test to verify the fix
2. Existing tests pass
3. Verified this in the extractor tool, but it looks a tiny bit funky.

Typically we remove characters by replacing it with a space ` `. But
this time, we replace it with some spaces _and_ an `@` character that
didn't exist at that specific position. If you look at the diff above,
you will notice that `)` was replaced with `@`.

That's why in the extractor tool it is highlighted that it could extract
it, but it's just funny looking because it highlights `)md:bg-red-500`

<img width="1816" alt="image"
src="https://github.com/user-attachments/assets/57e6a3ac-bfd5-4cad-a1ce-0039b4d7d9b5"
/>
2025-03-28 14:37:54 +01:00
Robin Malfait
c3ae9d1567
Improve changelog for @source not (#17375)
We didn't add a changelog for the PR
(https://github.com/tailwindlabs/tailwindcss/pull/17255) and there are a
few things we need to talk about. So opened this PR to get everything in
and once we're happy we can merge it in one go instead of changing on
`main` directly.

---------

Co-authored-by: Philipp Spiess <hello@philippspiess.com>
2025-03-28 11:32:10 +00:00
depfu[bot]
ec2f3bb1ad
Update @types/react 19.0.10 → 19.0.12 (patch) (#17377)
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/react (19.0.10 → 19.0.12) ·
[Repo](https://github.com/DefinitelyTyped/DefinitelyTyped)





Sorry, we couldn't find anything useful about this release.











---
![Depfu
Status](https://depfu.com/badges/edd6acd35d74c8d41cbb540c30442adf/stats.svg)

[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>
2025-03-28 10:56:17 +01:00
Jordan Pittman
3e53e25669
Add bg-{top,bottom}-{left,right} utilities (#17378)
We’re using this naming for `mask-*` and `mask-radial-at-*` position
utilities and we want to be consistent. The old ones for
`background-position` will stay but are deprecated

---------

Co-authored-by: Robin Malfait <malfait.robin@gmail.com>
2025-03-27 12:43:02 +01:00
Robin Malfait
eecb6f7476
A bit of cleanup (#17394)
Was working on another issue and noticed that I wanted these but they
aren't related to any of the issues. So opening a separate PR to do some
internal cleanup.
2025-03-26 12:08:53 -04:00
Robin Malfait
224ce0b19b
update changelog 2025-03-26 15:47:28 +01:00
Robin Malfait
b0c48c3de9
Fix symlink issues when resolving @source directives (#17391)
This PR fixes some issues related to symlinks when using them in the
`@source` directive.

Fixes: #16765
Fixes: #16038

## Test plan

1. Added tests to prove this works
   - Added a recursive symlink test as well to make sure we don't hang
2. Existing tests still pass


[ci-all]
2025-03-26 08:11:55 -04:00
Philipp Spiess
18365fff6c Prepare v4.0.17 release 2025-03-26 12:15:19 +01:00
Jordan Pittman
3dcd615b02
Fix Ruby files causing the CLI to hang (#17383)
Fixes #17379

The preprocessor we added to detect embedded languages uses a back
reference and given a long enough file with certain byte / character
patterns it'll cause what appears to be an indefinite hang (might just
be catastrophically exponential backtracking but not sure)

This replaces the one regex w/ back references with two, anchored,
multi-line regexes

Now we search for all the starting & ending delimiters in the file. We
then loop over all the starting delimiters, find the paired ending one,
and preprocess the content inside

---------

Co-authored-by: Philipp Spiess <hello@philippspiess.com>
2025-03-26 11:00:10 +01:00
Robin Malfait
c45616ff91
update changelog 2025-03-25 15:55:46 +01:00
Robin Malfait
1ef97759e3
Add @source not support (#17255)
This PR adds a new source detection feature: `@source not "…"`. It can
be used to exclude files specifically from your source configuration
without having to think about creating a rule that matches all but the
requested file:

```css
@import "tailwindcss";
@source not "../src/my-tailwind-js-plugin.js";
```

While working on this feature, we noticed that there are multiple places
with different heuristics we used to scan the file system. These are:

- Auto source detection (so the default configuration or an `@source
"./my-dir"`)
- Custom sources ( e.g. `@source "./**/*.bin"` — these contain file
extensions)
- The code to detect updates on the file system

Because of the different heuristics, we were able to construct failing
cases (e.g. when you create a new file into `my-dir` that would be
thrown out by auto-source detection, it'd would actually be scanned). We
were also leaving a lot of performance on the table as the file system
is traversed multiple times for certain problems.

To resolve these issues, we're now unifying all of these systems into
one `ignore` crate walker setup. We also implemented features like
auto-source-detection and the `not` flag as additional _gitignore_ rules
only, avoid the need for a lot of custom code needed to make decisions.

High level, this is what happens after the now:

- We collect all non-negative `@source` rules into a list of _roots_
(that is the source directory for this rule) and optional _globs_ (that
is the actual rules for files in this file). For custom sources (i.e
with a custom `glob`), we add an allowlist rule to the gitignore setup,
so that we can be sure these files are always included.
- For every negative `@source` rule, we create respective ignore rules.
- Furthermore we have a custom filter that ensures files are only read
if they have been changed since the last time they were read.

So, consider the following setup:

```css
/* packages/web/src/index.css */
@import "tailwindcss";
@source "../../lib/ui/**/*.bin";
@source not "../../lib/ui/expensive.bin";
```

This creates a git ignore file that (simplified) looks like this:

```gitignore
# Auto-source rules
*.{exe,node,bin,…}
*.{css,scss,sass,…}
{node_modules,git}/

# Custom sources can overwrite auto-source rules
!lib/ui/**/*.bin

# Negative rules
lib/ui/expensive.bin
```

We then use this information _on top of your existing `.gitignore`
setup_ to resolve files (i.e so if your `.gitignore` contains rules e.g.
`dist/` this line is going to be added _before_ any of the rules lined
out in the example above. This allows negative rules to allow-list your
`.gitignore` rules.

To implement this, we're rely on the `ignore` crate but we had to make
various changes, very specific, to it so we decided to fork the crate.
All changes are prefixed with a `// CHANGED:` block but here are the
most-important ones:

- We added a way to add custom ignore rules that _extend_ (rather than
overwrite) your existing `.gitignore` rules
- We updated the order in which files are resolved and made it so that
more-specific files can allow-list more generic ignore rules.
- We resolved various issues related to adding more than one base path
to the traversal and ensured it works consistent for Linux, macOS, and
Windows.

## Behavioral changes

1. Any custom glob defined via `@source` now wins over your `.gitignore`
file and the auto-content rules.
   - Resolves #16920
3. The `node_modules` and `.git` folders as well as the `.gitignore`
file are now ignored by default (but can be overridden by an explicit
`@source` rule).
   - Resolves #17318
   - Resolves #15882
4. Source paths into ignored-by-default folders (like `node_modules`)
now also win over your `.gitignore` configuration and auto-content
rules.
    -  Resolves #16669
5. Introduced `@source not "…"` to negate any previous rules.
   - Resolves #17058
6. Negative `content` rules in your legacy JavaScript configuration
(e.g. `content: ['!./src']`) now work with v4.
   - Resolves #15943 
7. The order of `@source` definitions matter now, because you can
technically include or negate previous rules. This is similar to your
`.gitingore` file.
9. Rebuilds in watch mode now take the `@source` configuration into
account
   - Resolves #15684

## Combining with other features

Note that the `not` flag is also already compatible with [`@source
inline(…)`](https://github.com/tailwindlabs/tailwindcss/pull/17147)
added in an earlier commit:

```css
@import "tailwindcss";
@source not inline("container");
```

## Test plan

- We added a bunch of oxide unit tests to ensure that the right files
are scanned
- We updated the existing integration tests with new `@source not "…"`
specific examples and updated the existing tests to match the subtle
behavior changes
- We also added a new special tag `[ci-all]` that, when added to the
description of a PR, causes the PR to run unit and integration tests on
all operating systems.

[ci-all]

---------

Co-authored-by: Philipp Spiess <hello@philippspiess.com>
2025-03-25 15:54:41 +01:00
Robin Malfait
f44cfffaa3
use correct heading level for v4.0.15 2025-03-25 15:52:51 +01:00
Robin Malfait
acaccf7fcb
fix typo 2025-03-25 15:52:41 +01:00
Robin Malfait
1c50b5c16c
Prepare v4.0.16 release (#17372)
Prepare the 4.0.16 release.

~~Also added a commit to mark the `--value('…')` and `--modifier('…')`
with literals strings as an experimental feature (aka not shipped in
this PR). But we can revert that commit if we still want to ship it in
4.0.16 instead of 4.1.~~

---------

Co-authored-by: Philipp Spiess <hello@philippspiess.com>
v4.0.16
2025-03-25 15:30:32 +01:00
Jordan Pittman
bd501e8511
Add ::-webkit-details-marker pseudo to marker variant (#17362)
See #17360

This PR updates the `marker` variant to also target the marker present
in `<summary>` elements in WebKit browsers. Chromium uses `::marker` and
is therefore already covered.

---------

Co-authored-by: Philipp Spiess <hello@philippspiess.com>
2025-03-25 13:22:00 +01:00
Philipp Spiess
e8715d081e
Extract keyframe name when followed by comma (#17352)
Fixes #17332

This PR ensures that keyframes are emitted even when they are referenced
following a comma, e.g.:

```css
@theme {
  --animate-test: 500ms both fade-in, 1000ms linear 500ms spin infinite;
                                 /* ^ */

  @keyframes fade-in {
    from {
      opacity: 0%;
    }
    to {
      opacity: 100%;
    }
  }
}
```

## Test plan

Added a unit test to capture the issue from #17332
2025-03-24 12:25:41 +01:00
Rudi Visser
baa016a1c9
Add Input & Output check to CLI (#17311)
Throw an error if the input and output file for the CLI are identical.

---------

Co-authored-by: Philipp Spiess <hello@philippspiess.com>
Co-authored-by: Robin Malfait <malfait.robin@gmail.com>
2025-03-24 12:00:36 +01:00
Robin Malfait
711b9cd0db
Pre process Slim templates embedded in Ruby files (#17336)
This PR fixes an issue where embedded Slim templates inside of Ruby
files are not pre processed because we pre process based on a file
extension.

This PR also handles embedded SLIM templates using the following syntax:

```rb
slim_template <<~SLIM
  .flex
    .flex-1
      h1 Hello World
    .flex-1
      p This is a test
SLIM
```

~~As far as I can tell, this is only a Slim template thing and not a
Haml template thing but I could be wrong here. See:
https://viewcomponent.org/guide/templates.html#interpolations~~

The ViewComponent package handles anything that looks like
`{lang}_template`, so the lang here will be used as the pre processing
language for now.

Fixes: #17334

# Test plan

1. Added test for this
2. Existing tests pass
3. Made sure that the snippet from the issue works as expected:

Added an example where we have a `slim_template` and a `svelte_template`
to prove that it embeds based on the language. I also added a
`html_template` with Svelte syntax to really make sure that that
_doesn't_ work.

<img width="1816" alt="image"
src="https://github.com/user-attachments/assets/35564a32-9c46-4b51-bb1f-e02f4ffe8b01"
/>
2025-03-24 11:58:37 +01:00
Philipp Spiess
fac8f7df62
Vite: Emit build dependencies on partial rebuilds (#17347)
Closes #17339

This PR fixes an issue that caused changes to `@import`-ed CSS files to
no longer rebuild the stylesheet after a change was made to a template
file.

The change in the template file causes a fast-path in the Vite plugin
now after changes in 4.0.8: _partial rebuilds_. For that branch we do
not need to re-evaluate your input CSS since we know only the candidate
list changed. However, we still need to emit all build dependencies as
via `addWatchFile(…)`, otherwise Vite will not correctly register
updates for these dependencies anymore.

## Test plan

- Updated the kitchen-sink Vite update tests to ensure that an
`@import`-ed CSS file can be updated even after a partial rebuild.
- Ensure this works in our Vite playground
2025-03-24 11:54:55 +01:00
Philipp Spiess
42f68bb359
Fix changelog (#17348)
This change was added in #17320 which was not released yet, see commit
order on `main`:
https://github.com/tailwindlabs/tailwindcss/commits/main/
2025-03-24 11:39:22 +01:00
depfu[bot]
1c481b81c7
Update all of nextjs 15.2.1 → 15.2.3 (patch) (#17337) 2025-03-24 11:26:05 +01:00
Robin Malfait
5426baf358
Fix class extraction followed by ( in Pug (#17320)
This PR fixes an issue where a class shorthand in Pug followed by a `(`
is not properly extracted.

```html
<template lang="pug">
.text-sky-600.bg-neutral-900(title="A tooltip") This div has an HTML attribute.
</template>
```

The `text-sky-600` is extracted, but the `bg-neutral-900` is not.

Fixes: #17313

# Test plan

1. Added test to cover this case
2. Existing tests pass (after a few small adjustments due to _more_
extracted candidates, but definitely not _less_)
3. Verified against the original issue (top is before, bottom is this
PR)
<img width="1307" alt="image"
src="https://github.com/user-attachments/assets/68a0529f-63ad-477d-a342-e3f91c5a1690"
/>

We had this exact same bug in Slim
(https://github.com/tailwindlabs/tailwindcss/pull/17278). Since Pug,
Slim and Haml are the only pre processors we have right now with this
dot-separated class notation I also double checked the Haml
pre-processor if this is an issue or not (and it's already covered
there).

<img width="1263" alt="image"
src="https://github.com/user-attachments/assets/c658168b-d124-46c9-9ec0-9697151a57bf"
/>
2025-03-21 15:43:37 +01:00
Jordan Pittman
91c0d56d0f Revert "Temporarily revert changes to `@utility"
This reverts commit 1aab04cebff39a5a1b89ff22c6655cf1f549b7a1.
2025-03-20 17:00:23 -04:00
Jordan Pittman
498b06f2d9 Fix the other two workflows v4.0.15 2025-03-20 16:38:19 -04:00
Jordan Pittman
1aab04cebf Temporarily revert changes to `@utility
The github release workflow is currently broken on the 4.0.15 tag for whatever reason and we need to get the release out
2025-03-20 16:21:48 -04:00
Jordan Pittman
508746b996 Remove fetch-tags from release workflow
The current checkout action can encounter a bug where, if this workflow was triggered by a tag, this breaks
2025-03-20 15:55:21 -04:00
Robin Malfait
250c843341
Add suggestions when --spacing(--value(integer, number)) is used (#17308)
This PR adds suggestions to CSS based functional utilities when the
`--spacing(…)` function is used.

Given this CSS:

```css
@import "tailwindcss";

@theme {
  --spacing: 0.25rem;
  --spacing-custom: 123px;
}

@utility with-custom-spacing-* {
  size: --value(--spacing);
}

@utility with-integer-spacing-* {
  size: --spacing(--value(integer));
}

@utility with-number-spacing-* {
  size: --spacing(--value(number));
}
```
    
And this HTML:
    
```html
<div class="with-custom-spacing-custom"></div>
<div class="with-custom-spacing-0"></div>
<div class="with-custom-spacing-0.5"></div>
<div class="with-custom-spacing-1"></div>
<div class="with-custom-spacing-1.5"></div>

<div class="with-integer-spacing-custom"></div>
<div class="with-integer-spacing-0"></div>
<div class="with-integer-spacing-0.5"></div>
<div class="with-integer-spacing-1"></div>
<div class="with-integer-spacing-1.5"></div>

<div class="with-number-spacing-custom"></div>
<div class="with-number-spacing-0"></div>
<div class="with-number-spacing-0.5"></div>
<div class="with-number-spacing-1"></div>
<div class="with-number-spacing-1.5"></div>
```
    
Play: https://play.tailwindcss.com/tYDaSNiNtS


Then you will see the following suggestions:

```json
[
  "with-custom-spacing-custom",

  "with-integer-spacing-0",
  "with-integer-spacing-1",
  "with-integer-spacing-2",
  "with-integer-spacing-3",
  "with-integer-spacing-4",
  "with-integer-spacing-5",
  "with-integer-spacing-6",
  "with-integer-spacing-7",
  "with-integer-spacing-8",
  "with-integer-spacing-9",
  "with-integer-spacing-10",
  "with-integer-spacing-11",
  "with-integer-spacing-12",
  "with-integer-spacing-14",
  "with-integer-spacing-16",
  "with-integer-spacing-20",
  "with-integer-spacing-24",
  "with-integer-spacing-28",
  "with-integer-spacing-32",
  "with-integer-spacing-36",
  "with-integer-spacing-40",
  "with-integer-spacing-44",
  "with-integer-spacing-48",
  "with-integer-spacing-52",
  "with-integer-spacing-56",
  "with-integer-spacing-60",
  "with-integer-spacing-64",
  "with-integer-spacing-72",
  "with-integer-spacing-80",
  "with-integer-spacing-96",

  "with-number-spacing-0",
  "with-number-spacing-0.5",
  "with-number-spacing-1",
  "with-number-spacing-1.5",
  "with-number-spacing-2",
  "with-number-spacing-2.5",
  "with-number-spacing-3",
  "with-number-spacing-3.5",
  "with-number-spacing-4",
  "with-number-spacing-5",
  "with-number-spacing-6",
  "with-number-spacing-7",
  "with-number-spacing-8",
  "with-number-spacing-9",
  "with-number-spacing-10",
  "with-number-spacing-11",
  "with-number-spacing-12",
  "with-number-spacing-14",
  "with-number-spacing-16",
  "with-number-spacing-20",
  "with-number-spacing-24",
  "with-number-spacing-28",
  "with-number-spacing-32",
  "with-number-spacing-36",
  "with-number-spacing-40",
  "with-number-spacing-44",
  "with-number-spacing-48",
  "with-number-spacing-52",
  "with-number-spacing-56",
  "with-number-spacing-60",
  "with-number-spacing-64",
  "with-number-spacing-72",
  "with-number-spacing-80",
  "with-number-spacing-96"
]
```

This is because `--spacing(--value(number))` will include all default
spacing scale suggestions we use. And `--pacing(--value(integer))` will
include the same list but without the floating point numbers.

Follow up PR for: https://github.com/tailwindlabs/tailwindcss/pull/17304
2025-03-20 19:06:07 +00:00
Robin Malfait
a3316f2ef4
Add support for literal values in --value('…') and --modifier('…') (#17304)
This PR adds support for literal values inside the `--value('…')` and
`--modifier('…')` functions. This allows you to safelist some known
values you want to use:

E.g.:

```css
@utility tab-* {
  tab-size: --value('revert', 'initial');
}
```

This allows you to use `tab-revert` and `tab-initial` for example.
2025-03-20 19:02:02 +00:00
Philipp Spiess
4c57d9f734
Prepare v4.0.15 release (#17302)
<!--

👋 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

-->
2025-03-20 17:51:30 +01:00
Philipp Spiess
40a76e3380
Revert "Don't use color-mix(…) on currentColor (#17247)" and work around Preflight crash (#17306)
Closes #17194.

This reverts commit d6d913ec39e2a4cc0a70e9d21c484c6ed95d40ae.

The initial fix does breaks older versions of Chrome (where text won't
render with a color for the placeholder at all anymore) and the usage of
the _relative colors_ features also means it'll require a much newer
version of Safari/Firefox/Chrome to work correctly. The implementation
was also wrong as it always set alpha to the specific percent instead of
applying it additively (note that this can be fixed with `calc(alpha *
opacity)` though).

Instead we decided to fix this by adding a `@supports` query to
Preflight that only targets browsers that aren't affected by the crash.
We currently use the following workaround:

```css
/*
  Set the default placeholder color to a semi-transparent version of the current text color in browsers that do not
  crash when using `color-mix(…)` with `currentColor`. (https://github.com/tailwindlabs/tailwindcss/issues/17194)
*/

@supports (not (-webkit-appearance: -apple-pay-button)) /* Not Safari */ or
  (contain-intrinsic-size: 1px) /* Safari 17+ */ {
  ::placeholder {
    color: color-mix(in oklab, currentColor 50%, transparent);
  }
}
```

## Test plan

When testing the `color-mix(currentColor)` vs `oklab(from currentColor
…)` we created the following support matrix. I'm extending it with _our
fix_ which is the fix ended up using:

| Browser | Version | `color-mix(… currentColor …)` | `oklab(from
currentColor …)` | `@supports { color-mix(…) }` |
| ------- | ------- | ----------------------------- |
---------------------------- | ------- |
| Chrome | 111 |  |  |  |
| Chrome | 116 |  |  |  |
| Chrome | 131+ |  |  |  |
| Safari | 16.4 | 💥 |  |  |
| Safari | 16.6+ |  |  |  |
| Safari | 18+ |  |  |  |
| Firefox | 128 |  |  |  |
| Firefox | 133 |  |  |  |

Note that on Safari 16, this change makes it so that the browser does
not crash yet it still won't work either. That's because now the browser
will fall back to the default placeholder color instead. We used the
following play to test the fix: https://play.tailwindcss.com/RF1RYbZLKY
2025-03-20 17:43:32 +01:00
Philipp Spiess
3f313b4eb2
Ensure that the CSS file rebuilds if a new CSS variable is used from templates (#17301)
Fixes #17288

This PR fixes an issue where changes in template files that _only mark a
new CSS variable as used_ was not causing the CSS file to rebuilds.

This also fixes a flaky integration test that was caused by a missing
`await` line on the final assertion (causing it to sometimes run the
assertion in time while the test runner was still running).

## Test plan

Turns out we already had an integration test for this but it wasn't
correctly running due to the missing await.
2025-03-20 12:52:02 +01:00
Philipp Spiess
ca7b10e7d3
Make --theme(…) return CSS variables (#17036)
Closes #16945

This PR changes the `--theme(…)` function now return CSS `var(…)`
definitions unless used in places where `var(…)` is not valid CSS (e.g.
in `@media (width >= theme(--breakpoint-md))`):

```css
/* input */
@theme {
  --color-red: red;
}
.red {
  color: --theme(--color-red);
}

/* output */
:root, :host {
  --color-red: red;
}
.red {
  color: var(--color-red);
}
```

Furthermore, this adds an `--theme(… inline)` option to the `--theme(…)`
function to force the resolution to be inline, e.g.:

```css
/* input */
@theme {
  --color-red: red;
}
.red {
  color: --theme(--color-red inline);
}

/* output */
.red {
  color: red;
}
```

This PR also changes preflight and the default theme to use this new
`--theme(…)` function to ensure variables are prefixed correctly.

## Test plan

- Added unit tests and a test that pulls in the whole preflight under a
prefix theme.
2025-03-20 12:51:22 +01:00
Philipp Spiess
a1acaeeee0
Export PluginUtils from tailwindcss/plugin (#17299)
Closes #17293

We used to export this in v3 so might as well bring it back for the
`tailwindcss/plugin` export list.
2025-03-20 12:19:45 +01:00
Philipp Spiess
503bad4e75
Use bun-baseline for all x64 builds (#17267)
Closes #17259

This PR now also updates the MacOS x64 build to use `bun-baseline`,
meaning all x64 builds now use baseline for the improved hardware
compatibility.

Co-authored-by: Robin Malfait <malfait.robin@gmail.com>
2025-03-20 12:16:04 +01:00
Robin Malfait
f369e22172
Fix class extraction followed by ( in Slim (#17278)
This PR fixes an issue where using the class shorthand in Slim
templates, followed by an `(` results in the last class being ignored.

E.g.:

```slim
body.border-t-4.p-8(class="#{body_classes}" data-hotwire-native="#{hotwire_native_app?}" data-controller="update-time-zone")
```

This is because we will eventually extract `p-8` but it's followed by an
invalid boundary character `(`.

To solve this, we make sure to replace the `(` with a space. We already
do a similar thing when the classes are followed by an `[`.

One caveat, we _can_ have `(` in our classes, like `bg-(--my-color)`.
But in my testing this is not something that can be used in the
shorthand version.

E.g.:
```slim
div.bg-(--my-color)
```

Compiles to:
```html
<div --my-color="" class="bg-"></div>
```

So I didn't add any special handling for this. Even when trying to
escape the `(`, `-` and `)` characters, it still doesn't work. E.g.:

```slim
div.bg-\(--my-color\)
```

Compiles to:
```html
<div class="bg-">\(--my-color\)</div>
```

# Test plan

1. Added test for the issue
2. Existing tests pass
3. Verified via the extractor tool:

| Before | After |
| --- | --- |
| <img width="958" alt="image"
src="https://github.com/user-attachments/assets/f72c420e-5429-424f-a01d-12f724062bf2"
/> | <img width="958" alt="image"
src="https://github.com/user-attachments/assets/b0cc8f2f-97a8-4fca-8813-3bb1da8d99a8"
/> |

---

Fixes: #17277
2025-03-19 09:50:30 -04:00
Robin Malfait
d698c10836
Ensure multiple --value(…) or --modifier(…) calls don't delete subsequent declarations (#17273)
This PR fixes a bug in the handling of `@utility`. Essentially if you
had a declaration where you used a `--modifier(…)` _and_ a `--value(…)`
and both caused the declaration to be removed, the declaration after the
current one would be removed as well.

This happened because 2 reasons:

1. Once we removed the declaration when we handled `--modifier(…)`, we
didn't stop the walk and kept going.
2. The `replaceWith(…)` code allows you to call the function multiple
times but immediately mutates the AST. This means that if you call it
multiple times that you are potentially removing / updating nodes
followed by the current one.

E.g.:

```css
@utility mask-r-* {
  --mask-right: linear-gradient(to left, transparent, black --value(percentage));
  --mask-right: linear-gradient(
    to left,
    transparent calc(var(--spacing) * --modifier(integer)),
    black calc(var(--spacing) * --value(integer))
  );
  mask-image: var(--mask-linear), var(--mask-radial), var(--mask-conic);
}
```

If this is used as `mask-r-10%`, then the first definition of
`--mask-right` is kept, but the second definition of `--mask-right` is
deleted because both `--modifier(integer)` and `--value(integer)` do not
result in a valid value.

However, the `mask-image` declaration was also removed because the
`replaceWith(…)` function was called twice. Once for
`--modifier(integer)` and once for `--value(integer)`.

# Test plan

1. Added a test to cover this case.
2. Existing tests pass.
3. Added a hard error if we call `replaceWith(…)` multiple times.
2025-03-19 13:25:53 +00:00
Devon Govett
cec7f0557b
Fix segmentation fault when loading @tailwindcss/oxide in a Worker thread (#17276)
When Tailwind is loaded in a Node Worker thread, it currently causes a
segmentation fault on Linux when the thread exits. This is due to a
longstanding issue in Rust that affects all native modules:
https://github.com/rust-lang/rust/issues/91979. I reported this years
ago but unfortunately it is still not fixed, and seems to have gotten
worse in Rust 1.83.0 and later. Looks like Tailwind recently updated
Rust versions and this issue started appearing when run in tools like
Parcel that use worker threads.

The workaround is to prevent the native module from ever being unloaded.
One way to do that is to always load the native module in the main
thread in addition to workers, but this is hard to enforce.
@Brooooooklyn found another method, which is to use a linker option for
this. I tested this on an Ubuntu system and verified it fixed the issue.
You can test with the following script.

```js
// test.js
const {Worker} = require('worker_threads');
new Worker('./worker.js');

// worker.js
require('@tailwindcss/oxide');
```

Without this change, a segmentation fault will occur.

---------

Co-authored-by: Jordan Pittman <jordan@cryptica.me>
2025-03-18 16:28:20 -04:00
Martijn Cuppens
1564bf092b
Remove redundant line-height from body (#15212)
It was added in #2729 to override line heights set on the body by
modern-normalize. However, it appears that modern-normalize never
included any line-height definitions—only a font-family rule was
present.

Ref:
https://github.com/sindresorhus/modern-normalize/blob/v1.1.0/modern-normalize.css

---------

Co-authored-by: Philipp Spiess <hello@philippspiess.com>
2025-03-18 12:23:49 +01:00
Robin Malfait
d7c81164da
Pre process <template lang="…"> in Vue files (#17252)
This PR fixes an issue where `<template lang="…">…</template>` in Vue
files should be handled as-if it's the language specified in the `lang`
attribute.

To do this, we added a new Vue pre processor and run the content through
the same pre processor logic as we do for other languages.

Fixes: #17211

# Test plan

1. Added a test to verify this works
2. Existing tests still work

Visually verified against the reproduction in the issue:

| Before | After |
| --- | --- |
| <img width="1273" alt="image"
src="https://github.com/user-attachments/assets/d1accdeb-97cf-48ef-83fb-978832b3e599"
/> | <img width="1273" alt="image"
src="https://github.com/user-attachments/assets/ab7ec19c-b6c4-43be-8845-096ff4e58808"
/> |

---------

Co-authored-by: Adam Wathan <adam.wathan@gmail.com>
2025-03-17 13:54:37 +00:00
Benoît Rouleau
ebfde316e1
Add safe alignment utilities (#14607)
Fixes #7929 and #12916

This PR adds [safe alignment
utilities](https://www.stefanjudis.com/today-i-learned/safe-unsafe-alignment-in-css-flexbox/)
to Tailwind 4. I opted to include them for every justify/align
content/items/self property, but only for the `end` and `center` values.
I know that it doesn't make sense for `start` (as the point of safe
alignment is to fall back to `start` when it overflows), but I'm not
sure about `space-between`, `space-around`, or other values. I certainly
never encountered a situation where I needed `safe` with those.
2025-03-17 14:09:15 +01:00