This commit is contained in:
Robin Malfait 2026-05-08 22:03:59 +02:00 • committed by GitHub
parent 59936c6cbb
commit 588bd7371f
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
28 changed files with 75 additions and 104 deletions

View file

@ -9,14 +9,18 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
### Added
- _Experimental_: add `@container-size` utility ([#18901](https://github.com/tailwindlabs/tailwindcss/pull/18901))
- _Experimental_: add `scrollbar-{auto,thin,none}` utilities for `scrollbar-width`, and `scrollbar-thumb-*` / `scrollbar-track-*` color utilities for `scrollbar-color` ([#19981](https://github.com/tailwindlabs/tailwindcss/pull/19981), [#20019](https://github.com/tailwindlabs/tailwindcss/pull/20019))
- Allow using `@variant` with stacked variants (e.g. `@variant hover:focus { … }`) ([#19996](https://github.com/tailwindlabs/tailwindcss/pull/19996))
- Allow using `@variant` with compound variants (e.g. `@variant hover, focus { … }`) ([#19996](https://github.com/tailwindlabs/tailwindcss/pull/19996))
- Support `--default(…)` in `--value(…)` and `--modifier(…)` for functional `@utility` definitions ([#19989](https://github.com/tailwindlabs/tailwindcss/pull/19989))
## [4.3.0] - 2026-05-08
### Added
- Add `@container-size` utility ([#18901](https://github.com/tailwindlabs/tailwindcss/pull/18901))
- Add `scrollbar-{auto,thin,none}` utilities for `scrollbar-width`, and `scrollbar-thumb-*` / `scrollbar-track-*` color utilities for `scrollbar-color` ([#19981](https://github.com/tailwindlabs/tailwindcss/pull/19981), [#20019](https://github.com/tailwindlabs/tailwindcss/pull/20019))
- Add `scrollbar-gutter-*` utilities ([#20018](https://github.com/tailwindlabs/tailwindcss/pull/20018))
- Add `zoom-*` utilities ([#20020](https://github.com/tailwindlabs/tailwindcss/pull/20020))
- Add `tab-*` utilities ([#20022](https://github.com/tailwindlabs/tailwindcss/pull/20022))
- Allow using `@variant` with stacked variants (e.g. `@variant hover:focus { … }`) ([#19996](https://github.com/tailwindlabs/tailwindcss/pull/19996))
- Allow using `@variant` with compound variants (e.g. `@variant hover, focus { … }`) ([#19996](https://github.com/tailwindlabs/tailwindcss/pull/19996))
- Support `--default(…)` in `--value(…)` and `--modifier(…)` for functional `@utility` definitions ([#19989](https://github.com/tailwindlabs/tailwindcss/pull/19989))
### Fixed
@ -25,10 +29,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Ensure CSS files containing `@variant` are processed by `@tailwindcss/vite` ([#19966](https://github.com/tailwindlabs/tailwindcss/pull/19966))
- Resolve imports relative to `base` when `result.opts.from` is not provided when using `@tailwindcss/postcss` ([#19980](https://github.com/tailwindlabs/tailwindcss/pull/19980))
- Canonicalization: preserve significant `_` whitespace in arbitrary values ([#19986](https://github.com/tailwindlabs/tailwindcss/pull/19986))
- Canonicalization: add parentheses when removing whitespace from arbitrary values would hurt readability ([#19986](https://github.com/tailwindlabs/tailwindcss/pull/19986))
- Canonicalization: add parentheses when removing whitespace from arbitrary values would hurt readability (e.g. `w-[calc(100%---spacing(60))]` → `w-[calc(100%-(--spacing(60)))]`) ([#19986](https://github.com/tailwindlabs/tailwindcss/pull/19986))
- Canonicalization: preserve the original unit in arbitrary values instead of normalizing to base units (e.g. `-mt-[20in]` → `mt-[-20in]`, not `mt-[-1920px]`) ([#19988](https://github.com/tailwindlabs/tailwindcss/pull/19988))
- Canonicalization: migrate arbitrary `:has()` variants from `[&:has(…)]` to `has-[…]` ([#19991](https://github.com/tailwindlabs/tailwindcss/pull/19991))
- Upgrade: don’t migrate inline `style` attributes ([#19918](https://github.com/tailwindlabs/tailwindcss/pull/19918))
- Upgrade: don’t migrate inline `style` attributes (e.g. `style="flex-grow: 1"` → `style="flex-grow: 1"`, not `style="grow: 1"`) ([#19918](https://github.com/tailwindlabs/tailwindcss/pull/19918))
- Allow multiple `@utility` definitions with the same name but different value types ([#19777](https://github.com/tailwindlabs/tailwindcss/pull/19777))
- Export missing `PluginWithConfig` type from `tailwindcss/plugin` to fix errors when inferring plugin config types ([#19707](https://github.com/tailwindlabs/tailwindcss/pull/19707))
- Ensure `start` and `end` legacy utilities without values do not generate CSS ([#20003](https://github.com/tailwindlabs/tailwindcss/pull/20003))
@ -4017,7 +4021,8 @@ No release notes
- Everything!
[unreleased]: https://github.com/tailwindlabs/tailwindcss/compare/v4.2.4...HEAD
[unreleased]: https://github.com/tailwindlabs/tailwindcss/compare/v4.3.0...HEAD
[4.3.0]: https://github.com/tailwindlabs/tailwindcss/compare/v4.2.4...v4.3.0
[4.2.4]: https://github.com/tailwindlabs/tailwindcss/compare/v4.2.3...v4.2.4
[4.2.3]: https://github.com/tailwindlabs/tailwindcss/compare/v4.2.2...v4.2.3
[4.2.2]: https://github.com/tailwindlabs/tailwindcss/compare/v4.2.1...v4.2.2

View file

@ -1,6 +1,6 @@
{
"name": "@tailwindcss/oxide-android-arm-eabi",
"version": "4.2.4",
"version": "4.3.0",
"repository": {
"type": "git",
"url": "git+https://github.com/tailwindlabs/tailwindcss.git",

View file

@ -1,6 +1,6 @@
{
"name": "@tailwindcss/oxide-android-arm64",
"version": "4.2.4",
"version": "4.3.0",
"repository": {
"type": "git",
"url": "git+https://github.com/tailwindlabs/tailwindcss.git",

View file

@ -1,6 +1,6 @@
{
"name": "@tailwindcss/oxide-darwin-arm64",
"version": "4.2.4",
"version": "4.3.0",
"repository": {
"type": "git",
"url": "git+https://github.com/tailwindlabs/tailwindcss.git",

View file

@ -1,6 +1,6 @@
{
"name": "@tailwindcss/oxide-darwin-x64",
"version": "4.2.4",
"version": "4.3.0",
"repository": {
"type": "git",
"url": "git+https://github.com/tailwindlabs/tailwindcss.git",

View file

@ -1,6 +1,6 @@
{
"name": "@tailwindcss/oxide-freebsd-x64",
"version": "4.2.4",
"version": "4.3.0",
"repository": {
"type": "git",
"url": "git+https://github.com/tailwindlabs/tailwindcss.git",

View file

@ -1,6 +1,6 @@
{
"name": "@tailwindcss/oxide-linux-arm-gnueabihf",
"version": "4.2.4",
"version": "4.3.0",
"repository": {
"type": "git",
"url": "git+https://github.com/tailwindlabs/tailwindcss.git",

View file

@ -1,6 +1,6 @@
{
"name": "@tailwindcss/oxide-linux-arm64-gnu",
"version": "4.2.4",
"version": "4.3.0",
"repository": {
"type": "git",
"url": "git+https://github.com/tailwindlabs/tailwindcss.git",

View file

@ -1,6 +1,6 @@
{
"name": "@tailwindcss/oxide-linux-arm64-musl",
"version": "4.2.4",
"version": "4.3.0",
"repository": {
"type": "git",
"url": "git+https://github.com/tailwindlabs/tailwindcss.git",

View file

@ -1,6 +1,6 @@
{
"name": "@tailwindcss/oxide-linux-x64-gnu",
"version": "4.2.4",
"version": "4.3.0",
"repository": {
"type": "git",
"url": "git+https://github.com/tailwindlabs/tailwindcss.git",

View file

@ -1,6 +1,6 @@
{
"name": "@tailwindcss/oxide-linux-x64-musl",
"version": "4.2.4",
"version": "4.3.0",
"repository": {
"type": "git",
"url": "git+https://github.com/tailwindlabs/tailwindcss.git",

View file

@ -1,6 +1,6 @@
{
"name": "@tailwindcss/oxide-wasm32-wasi",
"version": "4.2.4",
"version": "4.3.0",
"cpu": [
"wasm32"
],

View file

@ -1,6 +1,6 @@
{
"name": "@tailwindcss/oxide-win32-arm64-msvc",
"version": "4.2.4",
"version": "4.3.0",
"repository": {
"type": "git",
"url": "git+https://github.com/tailwindlabs/tailwindcss.git",

View file

@ -1,6 +1,6 @@
{
"name": "@tailwindcss/oxide-win32-x64-msvc",
"version": "4.2.4",
"version": "4.3.0",
"repository": {
"type": "git",
"url": "git+https://github.com/tailwindlabs/tailwindcss.git",

View file

@ -1,6 +1,6 @@
{
"name": "@tailwindcss/oxide",
"version": "4.2.4",
"version": "4.3.0",
"repository": {
"type": "git",
"url": "git+https://github.com/tailwindlabs/tailwindcss.git",

View file

@ -571,8 +571,9 @@ test(
async ({ exec, fs, expect }) => {
await exec('pnpm vite build')
expect((await fs.dumpFiles('./dist/**/*.css')).replace(/-([a-zA-Z0-9]*?)\.css/g, '-<hash>.css'))
.toMatchInlineSnapshot(`
expect(
(await fs.dumpFiles('./dist/**/*.css')).replace(/-([_a-zA-Z0-9]*?)\.css/g, '-<hash>.css'),
).toMatchInlineSnapshot(`
"
--- ./dist/assets/index-<hash>.css ---
.do-include-me {
@ -641,8 +642,9 @@ test(
async ({ exec, fs, expect }) => {
await exec('pnpm vite build')
expect((await fs.dumpFiles('./dist/**/*.css')).replace(/-([a-zA-Z0-9]*?)\.css/g, '-<hash>.css'))
.toMatchInlineSnapshot(`
expect(
(await fs.dumpFiles('./dist/**/*.css')).replace(/-([_a-zA-Z0-9]*?)\.css/g, '-<hash>.css'),
).toMatchInlineSnapshot(`
"
--- ./dist/assets/index-<hash>.css ---
@layer base {

View file

@ -1,6 +1,6 @@
{
"name": "@tailwindcss/browser",
"version": "4.2.4",
"version": "4.3.0",
"description": "A utility-first CSS framework for rapidly building custom user interfaces.",
"license": "MIT",
"main": "./dist/index.global.js",

View file

@ -1,6 +1,6 @@
{
"name": "@tailwindcss/cli",
"version": "4.2.4",
"version": "4.3.0",
"description": "A utility-first CSS framework for rapidly building custom user interfaces.",
"license": "MIT",
"repository": {

View file

@ -1,6 +1,6 @@
{
"name": "@tailwindcss/node",
"version": "4.2.4",
"version": "4.3.0",
"description": "A utility-first CSS framework for rapidly building custom user interfaces.",
"license": "MIT",
"repository": {

View file

@ -1,6 +1,6 @@
{
"name": "@tailwindcss/postcss",
"version": "4.2.4",
"version": "4.3.0",
"description": "PostCSS plugin for Tailwind CSS, a utility-first CSS framework for rapidly building custom user interfaces",
"license": "MIT",
"repository": {

View file

@ -1,6 +1,6 @@
{
"name": "@tailwindcss/standalone",
"version": "4.2.4",
"version": "4.3.0",
"private": true,
"description": "Standalone CLI for Tailwind CSS",
"license": "MIT",

View file

@ -1,6 +1,6 @@
{
"name": "@tailwindcss/upgrade",
"version": "4.2.4",
"version": "4.3.0",
"description": "A utility-first CSS framework for rapidly building custom user interfaces.",
"license": "MIT",
"repository": {

View file

@ -1,6 +1,6 @@
{
"name": "@tailwindcss/vite",
"version": "4.2.4",
"version": "4.3.0",
"description": "A utility-first CSS framework for rapidly building custom user interfaces.",
"license": "MIT",
"repository": {

View file

@ -1,6 +1,6 @@
{
"name": "@tailwindcss/webpack",
"version": "4.2.4",
"version": "4.3.0",
"description": "A webpack loader for Tailwind CSS v4.",
"license": "MIT",
"repository": {

View file

@ -1,6 +1,6 @@
{
"name": "tailwindcss",
"version": "4.2.4",
"version": "4.3.0",
"description": "A utility-first CSS framework for rapidly building custom user interfaces.",
"license": "MIT",
"repository": {

View file

@ -1,2 +0,0 @@
export const enableContainerSizeUtility = process.env.FEATURES_ENV !== 'stable'
export const enableScrollbarUtilities = process.env.FEATURES_ENV !== 'stable'

View file

@ -11503,7 +11503,6 @@ test('scrollbar-thumb', async () => {
css`
@theme {
--color-red-500: #ef4444;
--scrollbar-thumb-color-blue-500: #3b82f6;
}
@tailwind utilities;
`,
@ -11511,7 +11510,6 @@ test('scrollbar-thumb', async () => {
'scrollbar-thumb-red-500',
'scrollbar-thumb-red-500/50',
'scrollbar-thumb-red-500/[0.5]',
'scrollbar-thumb-blue-500',
'scrollbar-thumb-current',
'scrollbar-thumb-inherit',
'scrollbar-thumb-transparent',
@ -11532,7 +11530,6 @@ test('scrollbar-thumb', async () => {
:root, :host {
--color-red-500: #ef4444;
--scrollbar-thumb-color-blue-500: #3b82f6;
}
.scrollbar-thumb-\\[\\#0088cc\\] {
@ -11545,11 +11542,6 @@ test('scrollbar-thumb', async () => {
scrollbar-color: var(--tw-scrollbar-thumb) var(--tw-scrollbar-track);
}
.scrollbar-thumb-blue-500 {
--tw-scrollbar-thumb: var(--scrollbar-thumb-color-blue-500);
scrollbar-color: var(--tw-scrollbar-thumb) var(--tw-scrollbar-track);
}
.scrollbar-thumb-current {
--tw-scrollbar-thumb: currentcolor;
scrollbar-color: var(--tw-scrollbar-thumb) var(--tw-scrollbar-track);
@ -11628,7 +11620,6 @@ test('scrollbar-track', async () => {
css`
@theme {
--color-red-500: #ef4444;
--scrollbar-track-color-blue-500: #3b82f6;
}
@tailwind utilities;
`,
@ -11636,7 +11627,6 @@ test('scrollbar-track', async () => {
'scrollbar-track-red-500',
'scrollbar-track-red-500/50',
'scrollbar-track-red-500/[0.5]',
'scrollbar-track-blue-500',
'scrollbar-track-current',
'scrollbar-track-inherit',
'scrollbar-track-transparent',
@ -11657,7 +11647,6 @@ test('scrollbar-track', async () => {
:root, :host {
--color-red-500: #ef4444;
--scrollbar-track-color-blue-500: #3b82f6;
}
.scrollbar-track-\\[\\#0088cc\\] {
@ -11670,11 +11659,6 @@ test('scrollbar-track', async () => {
scrollbar-color: var(--tw-scrollbar-thumb) var(--tw-scrollbar-track);
}
.scrollbar-track-blue-500 {
--tw-scrollbar-track: var(--scrollbar-track-color-blue-500);
scrollbar-color: var(--tw-scrollbar-thumb) var(--tw-scrollbar-track);
}
.scrollbar-track-current {
--tw-scrollbar-track: currentcolor;
scrollbar-color: var(--tw-scrollbar-thumb) var(--tw-scrollbar-track);
@ -11866,18 +11850,7 @@ test('whitespace', async () => {
})
test('tab', async () => {
expect(
await compileCss(
css`
@theme {
--tab-size-github: 8;
}
@tailwind utilities;
`,
['tab-2', 'tab-8', 'tab-[12px]', 'tab-[3]'],
),
).toMatchInlineSnapshot(`
expect(await run(['tab-2', 'tab-8', 'tab-[12px]', 'tab-[3]'])).toMatchInlineSnapshot(`
"
.tab-2 {
tab-size: 2;

View file

@ -12,7 +12,6 @@ import {
} from './ast'
import type { Candidate, CandidateModifier, NamedUtilityValue } from './candidate'
import type { DesignSystem } from './design-system'
import { enableContainerSizeUtility, enableScrollbarUtilities } from './feature-flags'
import type { Theme, ThemeKey } from './theme'
import { compareBreakpoints } from './utils/compare-breakpoints'
import { DefaultMap } from './utils/default-map'
@ -2228,43 +2227,41 @@ export function createUtilities(theme: Theme) {
staticUtility('scroll-auto', [['scroll-behavior', 'auto']])
staticUtility('scroll-smooth', [['scroll-behavior', 'smooth']])
if (enableScrollbarUtilities) {
staticUtility('scrollbar-auto', [['scrollbar-width', 'auto']])
staticUtility('scrollbar-thin', [['scrollbar-width', 'thin']])
staticUtility('scrollbar-none', [['scrollbar-width', 'none']])
staticUtility('scrollbar-auto', [['scrollbar-width', 'auto']])
staticUtility('scrollbar-thin', [['scrollbar-width', 'thin']])
staticUtility('scrollbar-none', [['scrollbar-width', 'none']])
staticUtility('scrollbar-gutter-auto', [['scrollbar-gutter', 'auto']])
staticUtility('scrollbar-gutter-stable', [['scrollbar-gutter', 'stable']])
staticUtility('scrollbar-gutter-both', [['scrollbar-gutter', 'stable both-edges']])
{
let scrollbarColorProperties = () => {
return atRoot([
property('--tw-scrollbar-thumb', '#0000', '<color>'),
property('--tw-scrollbar-track', '#0000', '<color>'),
])
}
colorUtility('scrollbar-thumb', {
themeKeys: ['--scrollbar-thumb-color', '--color'],
handle: (value) => [
scrollbarColorProperties(),
decl('--tw-scrollbar-thumb', value),
decl('scrollbar-color', 'var(--tw-scrollbar-thumb) var(--tw-scrollbar-track)'),
],
})
colorUtility('scrollbar-track', {
themeKeys: ['--scrollbar-track-color', '--color'],
handle: (value) => [
scrollbarColorProperties(),
decl('--tw-scrollbar-track', value),
decl('scrollbar-color', 'var(--tw-scrollbar-thumb) var(--tw-scrollbar-track)'),
],
})
{
let scrollbarColorProperties = () => {
return atRoot([
property('--tw-scrollbar-thumb', '#0000', '<color>'),
property('--tw-scrollbar-track', '#0000', '<color>'),
])
}
colorUtility('scrollbar-thumb', {
themeKeys: ['--color'],
handle: (value) => [
scrollbarColorProperties(),
decl('--tw-scrollbar-thumb', value),
decl('scrollbar-color', 'var(--tw-scrollbar-thumb) var(--tw-scrollbar-track)'),
],
})
colorUtility('scrollbar-track', {
themeKeys: ['--color'],
handle: (value) => [
scrollbarColorProperties(),
decl('--tw-scrollbar-track', value),
decl('scrollbar-color', 'var(--tw-scrollbar-thumb) var(--tw-scrollbar-track)'),
],
})
}
staticUtility('scrollbar-gutter-auto', [['scrollbar-gutter', 'auto']])
staticUtility('scrollbar-gutter-stable', [['scrollbar-gutter', 'stable']])
staticUtility('scrollbar-gutter-both', [['scrollbar-gutter', 'stable both-edges']])
staticUtility('truncate', [
['overflow', 'hidden'],
['text-overflow', 'ellipsis'],
@ -5969,11 +5966,7 @@ export function createUtilities(theme: Theme) {
value = candidate.value.value
} else if (candidate.value.kind === 'named' && candidate.value.value === 'normal') {
value = 'normal'
} else if (
enableContainerSizeUtility &&
candidate.value.kind === 'named' &&
candidate.value.value === 'size'
) {
} else if (candidate.value.kind === 'named' && candidate.value.value === 'size') {
value = 'size'
}