Add scrollbar-gutter-* utilities (#20018)

This PR adds new `scrollbar-gutter-*` utilities. The API looks like
this:

| Class | CSS |
| -- | -- |
| `scrollbar-gutter-auto` | `scrollbar-gutter: auto` |
| `scrollbar-gutter-stable` | `scrollbar-gutter: stable` |
| `scrollbar-gutter-both` | `scrollbar-gutter: stable both-edges` |
This commit is contained in:
Robin Malfait 2026-05-08 21:13:06 +02:00 • committed by GitHub
parent c00da894dd
commit 2e1ccf7f11
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
7 changed files with 55 additions and 17 deletions

View file

@ -10,10 +10,11 @@ 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))
- _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))
- Add `scrollbar-gutter-*` utilities ([#20018](https://github.com/tailwindlabs/tailwindcss/pull/20018))
### Fixed

View file

@ -11014,6 +11014,9 @@ exports[`getClassList 1`] = `
"scroll-py-px",
"scroll-smooth",
"scrollbar-auto",
"scrollbar-gutter-auto",
"scrollbar-gutter-both",
"scrollbar-gutter-stable",
"scrollbar-none",
"scrollbar-thin",
"scrollbar-thumb-current",

View file

@ -215,12 +215,12 @@ test('Config files can affect the theme', async () => {
expect(pretty(compiler.build(['bg-primary', 'scrollbar-primary']))).toMatchInlineSnapshot(`
"
.bg-primary {
background-color: #c0ffee;
}
.scrollbar-primary {
scrollbar-color: #c0ffee;
}
.bg-primary {
background-color: #c0ffee;
}
"
`)
})

View file

@ -3953,6 +3953,10 @@ describe('matchUtilities()', () => {
expect(optimizeCss(await run(['scrollbar-[2px]', 'scrollbar-[#08c]', 'scrollbar-[#08c]/50'])))
.toMatchInlineSnapshot(`
"
.scrollbar-\\[2px\\] {
scrollbar-width: 2px;
}
.scrollbar-\\[\\#08c\\] {
scrollbar-color: #08c;
}
@ -3960,10 +3964,6 @@ describe('matchUtilities()', () => {
.scrollbar-\\[\\#08c\\]\\/50 {
scrollbar-color: oklab(59.9824% -.067 -.124 / .5);
}
.scrollbar-\\[2px\\] {
scrollbar-width: 2px;
}
"
`)
expect(optimizeCss(await run(['scrollbar-[2px]/50']))).toEqual('')
@ -4117,10 +4117,14 @@ describe('matchUtilities()', () => {
),
).toMatchInlineSnapshot(`
"
.scrollbar-2 {
.scrollbar-2, .scrollbar-\\[2px\\] {
scrollbar-width: 2px;
}
.scrollbar-\\[length\\:var\\(--my-width\\)\\] {
scrollbar-width: var(--my-width);
}
.scrollbar-\\[\\#fff\\] {
scrollbar-color: #fff;
}
@ -4129,10 +4133,6 @@ describe('matchUtilities()', () => {
scrollbar-color: oklab(100% 0 5.96046e-8 / .5);
}
.scrollbar-\\[2px\\] {
scrollbar-width: 2px;
}
.scrollbar-\\[color\\:var\\(--my-color\\)\\], .scrollbar-\\[color\\:var\\(--my-color\\)\\]\\/50 {
scrollbar-color: var(--my-color);
}
@ -4143,10 +4143,6 @@ describe('matchUtilities()', () => {
}
}
.scrollbar-\\[length\\:var\\(--my-width\\)\\] {
scrollbar-width: var(--my-width);
}
.scrollbar-\\[var\\(--my-color\\)\\], .scrollbar-\\[var\\(--my-color\\)\\]\\/50 {
scrollbar-color: var(--my-color);
}

View file

@ -131,6 +131,10 @@ export default [
'scroll-padding-bottom',
'scroll-padding-left',
'scrollbar-width',
'scrollbar-color',
'scrollbar-gutter',
'list-style-position',
'list-style-type',
'list-style-image',

View file

@ -11439,6 +11439,36 @@ test('scrollbar-width', async () => {
).toEqual('')
})
test('scrollbar-gutter', async () => {
expect(await run(['scrollbar-gutter-auto', 'scrollbar-gutter-stable', 'scrollbar-gutter-both']))
.toMatchInlineSnapshot(`
"
.scrollbar-gutter-auto {
scrollbar-gutter: auto;
}
.scrollbar-gutter-both {
scrollbar-gutter: stable both-edges;
}
.scrollbar-gutter-stable {
scrollbar-gutter: stable;
}
"
`)
expect(
await run([
'scrollbar-gutter',
'-scrollbar-gutter-auto',
'-scrollbar-gutter-stable',
'-scrollbar-gutter-both',
'scrollbar-gutter-auto/foo',
'scrollbar-gutter-stable/foo',
'scrollbar-gutter-both/foo',
]),
).toEqual('')
})
test('scrollbar-thumb', async () => {
expect(
await compileCss(

View file

@ -2218,6 +2218,10 @@ export function createUtilities(theme: Theme) {
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([