A scrollbar is drawn by the browser, so AsheeUI ships no `Scrollbar` component. It ships a
configuration entry and the stylesheet that reads it: the thickness of every scrollbar on the
page, the rounding of its thumb and track, the space the thumb keeps from the edge of the track,
the gutter reserved for it, and the two colours the theme supplies.

Set it once and every scroll container in the application wears it. There is nothing to render and
no component to find in the gallery: the provider writes the values into variables on the
document, and the stylesheet applies them.

```tsx demo="system/scrollbar-preview"
```

## Usage

State the entry under `components` in the configuration the provider receives:

```tsx
import { AsheeUIProvider } from "@asheeui/web";

<AsheeUIProvider
  config={{
    components: {
      scrollbar: { width: "12px", radius: "8px", thumbBorder: "2px" },
    },
  }}>
  {children}
</AsheeUIProvider>;
```

Every key is optional, and the defaults apply where you state nothing, including on a page that
never mentions `scrollbar` at all, because the resolved configuration always carries the
registered defaults. The snippet above is therefore how a product with a heavier scrollbar is
configured, not the minimum required. An `asheeui.config.ts` file that exports the same object
works identically, as [configuration](/concepts/configuration) describes.

The values are written into CSS custom properties on the document root before the first paint, by
the same script that writes the theme's colours: `--ashee-scrollbar-width`,
`--ashee-scrollbar-radius`, `--ashee-scrollbar-track-radius`, `--ashee-scrollbar-thumb-border`,
`--ashee-scrollbar-gutter` and `--ashee-scrollbar-fallback-width`. The stylesheet reads those
variables and never the configuration object, which is why a theme switch leaves them alone and
why a scroll container does not have to know the configuration exists.

## Configuration

| Key | Takes | Default |
| --- | --- | --- |
| `width` | Any CSS length: the thickness of the scrollbar, and the height of a horizontal one | `"10px"` |
| `radius` | Any CSS radius: the thumb's corners, and the track's while `trackRadius` is unstated | `"9999px"` |
| `trackRadius` | Any CSS radius, for the track alone | Falls back to `radius` |
| `thumbBorder` | Any CSS length: drawn as a transparent border on the thumb plus `padding-box` clipping, so it reads as breathing room between thumb and track | `"3px"` |
| `gutter` | `"auto"`, `"stable"` or `"stable both-edges"`: the native `scrollbar-gutter` value that reserves space for the scrollbar | `"stable"` |
| `fallbackWidth` | `"auto"`, `"thin"` or `"none"`: the native `scrollbar-width` keyword for engines that draw the scrollbar themselves | `"thin"` |

Colours are not among them. The thumb and track take the theme's `scrollbarThumb` and
`scrollbarTrack` colours, so they change with the theme rather than with this entry, and a theme
whose track is `transparent`, the light theme's, draws only the thumb. `gutter: "stable"` is
what stops a page shifting sideways when its content grows past a screen; `"stable both-edges"`
reserves the same room on both sides, for a centred column.

`fallbackWidth` is the bar an engine that draws its own scrollbar will take, written as the
`scrollbar-width` keyword the stylesheet reads from `--ashee-scrollbar-fallback-width`: `thin`
for the narrow bar the framework defaults to, `auto` for the engine's own thickness, and `none`
to draw no bar at all in a piece of content a reader still scrolls.

## Where it applies

The stylesheet styles `html`, `body` and **every** element, so the scrollbar of a nested pane
follows the same entry as the page's own: a card with a scrolling body, a table with a pinned
header, a textarea with more text than rows. The width, the rounding and the thumb border come
from the values above; the two colours come from the active theme.

What does not follow it:

- **The thickness and rounding are WebKit's.** The width, the track radius and the thumb's
  border are drawn through `::-webkit-scrollbar`, `::-webkit-scrollbar-track` and
  `::-webkit-scrollbar-thumb`, which Chromium and WebKit implement. An engine without those
  pseudo-elements, Firefox, gets the standard `scrollbar-color` and `scrollbar-width` instead,
  so it takes the colours and the `fallbackWidth` bar, and its exact thickness and rounding are
  the browser's own.
- **Overlay scrollbars belong to the platform.** Where the operating system draws a scrollbar
  over the content and fades it out, macOS's default, iOS, the platform paints it and may use
  none of this. No CSS can insist on a classic scrollbar there.
- **A frame is another document.** The scrollbar of an `iframe` belongs to the page inside it,
  and takes this stylesheet only if that page loads AsheeUI's styles.
- **A container can opt out.** The stylesheet also provides `.scrollbar-hide`, which keeps the
  element scrollable but sets `scrollbar-width: none`, hides the WebKit pseudo-elements and
  returns the gutter to `auto`; `.scrollable-hidden` is the earlier spelling of the same idea,
  without the gutter reset. The framework's own carousels, overlay backdrops and toast stacks
  carry the class, because a scrollbar there is noise. Everything else, the body, a page's own
  panes, is styled.

```tsx demo="system/scrollbar-opt-out"
```

An element that cannot scroll has nothing to draw, so the entry is invisible until content
overflows: no configuration is required for a page that never scrolls.

## Accessibility

- The two colours come from the theme, and the default track is transparent, so the thumb alone
  carries the scrollbar's contrast against the background. Keeping that pair readable is what
  `scrollbarThumb` and `scrollbarTrack` are for; the configuration entry changes shape, not
  contrast.
- The scrollbar is the browser's control: it is not focusable and not announced, and `width` is
  not a target-size guarantee. Scrolling also has to work from the keyboard and the wheel, which
  is the browser's behaviour and the reason nothing here removes `overflow`.
- `scrollbar-hide` removes the indicator, not the scrolling: the reader loses the only thing that
  said how much of the content is left. Use it where something else answers that question, a
  carousel's arrows, a marquee, a list with a count beside it, and not on a page's only scroller.
- `gutter: "stable"` reserves the scrollbar's room before it is needed, so content does not
  reflow when a page grows; a layout that measures itself on load should keep it.

## Native

The platform draws its own scroll indicator, so there is no entry in the compatibility matrix and
nothing to import: a React Native `ScrollView` can show or hide its indicator, but its shape and
colours are the platform's. See [React Native](/platforms/native).

## Related

```related keyboard, table, modal
```
