Overlay Scrollbar

The scroll cue for a padded, roundedsurface — a dialog panel, a bounded list. It’s painted over the content, so it costs no layout width: the declared padding renders symmetrically, and nothing shifts when the surface becomes scrollable. Floating menus (Dropdown, Listbox, Combobox) and full-bleed bodies keep the native scrollbar-thin — they have no symmetric padding for a gutter to steal from.

A native bar can’t do this. overflow: overlaywas removed from the platform, and whether bars float or take width is an OS setting a page can’t override — so the only choices were scrollbar-gutter: stable (no reflow, but the gutter is reserved on one side forever) or auto (symmetric at rest, but content lurches sideways when a bar appears).

Native (scrollbar-gutter: stable) vs overlay

Native — the gutter eats the right padding, even before you scroll.

Line 1 — content that runs past the bottom of the box.

Line 2 — content that runs past the bottom of the box.

Line 3 — content that runs past the bottom of the box.

Line 4 — content that runs past the bottom of the box.

Line 5 — content that runs past the bottom of the box.

Line 6 — content that runs past the bottom of the box.

Line 7 — content that runs past the bottom of the box.

Line 8 — content that runs past the bottom of the box.

Line 9 — content that runs past the bottom of the box.

Line 10 — content that runs past the bottom of the box.

Line 11 — content that runs past the bottom of the box.

Line 12 — content that runs past the bottom of the box.

Overlay — padding stays symmetric, the cue still shows.

Line 1 — content that runs past the bottom of the box.

Line 2 — content that runs past the bottom of the box.

Line 3 — content that runs past the bottom of the box.

Line 4 — content that runs past the bottom of the box.

Line 5 — content that runs past the bottom of the box.

Line 6 — content that runs past the bottom of the box.

Line 7 — content that runs past the bottom of the box.

Line 8 — content that runs past the bottom of the box.

Line 9 — content that runs past the bottom of the box.

Line 10 — content that runs past the bottom of the box.

Line 11 — content that runs past the bottom of the box.

Line 12 — content that runs past the bottom of the box.

Wiring: scrollbar-none + overflow-y-auto on the scroller; a relative ancestor that does notscroll (inside the scroller the thumb would scroll away with the content it tracks); refs to the scroller and to a wrapper around its content. Both boxes are observed — the scroller’s own box is usually pinned by a cap and never changes, so watching only it leaves the thumb stranded. insetkeeps the thumb clear of the corner radius (default 24, the dialog panel’s).

Theme