[ @sdxc/u/overflow ]
scrollbar-color
Themes a scroll container's scrollbar via the standard scrollbar-color property, supported by Firefox and modern Chromium alike through plain CSS.
import { scrollbarColor } from "@sdxc/u/overflow";Quick reference
Every documented call, beside the CSS it emits.
| Call | CSS |
|---|---|
u.scrollbarColor() | css({ scrollbarColor: "auto" }) |
u.scrollbarColor("neutral") | css({ scrollbarColor: "var(--ui-neutral-border) transparent" }) |
u.scrollbarColor("brand.strong", "neutral") | css({ scrollbarColor: "var(--ui-brand-border-strong) var(--ui-neutral-bg-tint)" }) |
u.scrollbarColor("color.neutral.400", "color.neutral.100") | css({ scrollbarColor: "var(--ui-color-neutral-400) var(--ui-color-neutral-100)" }) |
Examples
Basic example
Use scrollbarColor("neutral") to color the scrollbar thumb with a tone, leaving the track transparent. Scroll the box, or set your system to always show scrollbars, to see it:
This paragraph is taller than its box, so the last lines of it do not fit. Scroll to read the rest, while the page around the box stays exactly where it is.
<div
mix={[scroll("y"), scrollbarColor("neutral"), bs(24), is(72), maxIs("100%"), ...]}
>
<p mix={[...]}>
This paragraph is taller than its box, so the last lines of it do not fit. Scroll to read
the rest, while the page around the box stays exactly where it is.
</p>
</div>Thumb and track
Pass a second color to paint the track too, like scrollbarColor("brand.strong", "neutral"):
This paragraph is taller than its box, so the last lines of it do not fit. Scroll to read the rest, while the page around the box stays exactly where it is.
<div
mix={[
scroll("y"),
scrollbarColor("brand.strong", "neutral"),
bs(24),
is(72),
maxIs("100%"),
...,
]}
>
<p mix={[...]}>
This paragraph is taller than its box, so the last lines of it do not fit. Scroll to read
the rest, while the page around the box stays exactly where it is.
</p>
</div>Using palette shades
Pass palette paths, like scrollbarColor("color.brand.500", "color.brand.100"), for exact shades:
This paragraph is taller than its box, so the last lines of it do not fit. Scroll to read the rest, while the page around the box stays exactly where it is.
<div
mix={[
scroll("y"),
scrollbarColor("color.brand.500", "color.brand.100"),
bs(24),
is(72),
maxIs("100%"),
...,
]}
>
<p mix={[...]}>
This paragraph is taller than its box, so the last lines of it do not fit. Scroll to read
the rest, while the page around the box stays exactly where it is.
</p>
</div>Applying on a state
Wrap the call in a state utility to scope it to one selector.
u.hover(u.scrollbarColor())Responsive design
Wrap the call in a container query to scope it to one width.
u.at("md", u.scrollbarColor())Customizing your theme
Customizing colors
Define a palette as --ui-color-{name}-{50..950} and map a tone onto it with the --ui-{tone}-* variables, the way theme.css maps the built-in ones:
:root {
--ui-color-info-50: oklch(0.97 0.02 230);
--ui-color-info-200: oklch(0.88 0.06 230);
--ui-color-info-500: oklch(0.62 0.16 230);
--ui-color-info-600: oklch(0.52 0.18 230);
--ui-color-info-900: oklch(0.3 0.1 230);
--ui-info-bg-tint: var(--ui-color-info-50);
--ui-info-bg-solid: var(--ui-color-info-600);
--ui-info-fg: var(--ui-color-info-600);
--ui-info-fg-muted: var(--ui-color-info-500);
--ui-info-fg-emphasis: var(--ui-color-info-900);
--ui-info-fg-on-solid: white;
--ui-info-border: var(--ui-color-info-200);
--ui-info-border-strong: var(--ui-color-info-600);
--ui-info-ring: var(--ui-color-info-500);
}declare module "@sdxc/u" {
interface ColorPalettes {
info: true;
}
interface SemanticTones {
info: true;
}
}The new name is then accepted wherever the scale is:
scrollbarColor("info")Signature
u.scrollbarColor(thumb?: ColorValue | (string & {}), track?: ColorValue | (string & {}))