unscripted/ui

Scroll Area

A scroll container with a thin themed scrollbar and fade edges that appear only when there's more to scroll — styled scrollbars plus a scroll-state query, no JavaScript.

scrollbar-colorscrollable query

Restyling a scrollbar used to mean ::-webkit-scrollbar, a nonstandard pseudo-element that only Chromium and WebKit implemented. scrollbar-color and scrollbar-width are the standard, cross-engine replacement, and the top/bottom fades that once needed a scroll listener now come from a container query.

How it works

  • [scrollbar-width:thin] and [scrollbar-color:var(--border)_transparent] give you a slim scrollbar in your own theme tokens. The thumb picks up --border, so it flips automatically in dark mode. Two declarations replace the whole ::-webkit-scrollbar stack, and they work in Firefox too.
  • [scrollbar-gutter:stable] reserves the scrollbar’s space up front, so content doesn’t jump sideways the moment it becomes scrollable.
  • The fade edges are the fun part. The scroller is a [container-type:scroll-state] container, and each fade is a sticky gradient toggled by a scroll-state query: [@container_scroll-state(scrollable:top)]:opacity-100 shows the top fade only while there’s content hidden above, and scrollable:bottom does the mirror at the bottom. No scroll listener, no IntersectionObserver. The browser already knows whether the box can scroll each way.
  • Each fade uses a negative margin (-mb-6 / -mt-6) to cancel its own height, so it overlays the content instead of taking up scroll length, and pointer-events-none lets clicks pass through to the rows underneath.

The fallback story

scrollbar-color/scrollbar-width are newly Baseline, so nearly everywhere you get the thin themed bar; the odd older engine just shows its default scrollbar, still perfectly scrollable. Scroll-state queries are Chromium-only for now, so elsewhere the fade edges never appear. Nothing breaks: you keep an ordinary scroll box.

Browser support

Minimum stable version per engine, resolved at build time from MDN's browser-compat-data; Baseline status from the official web-features dataset. Everything degrades gracefully — the “when missing” column is the actual behavior, not a broken page.

FeatureChromeEdgeFirefoxSafariWhen missing
Styled scrollbars (scrollbar-color / scrollbar-width)Baseline 2025 · newly available1211216426.2You get the default platform scrollbar instead of the thin themed one — still fully scrollable.
Scroll-state query: scrollableLimited availability133133The fade edges never appear; the panel still scrolls normally.

† @supports can’t test @container descriptors, so the badge checks container-type: scroll-state — the scrollable query landed alongside it in Chrome 133.