Scroll Area

A panel with custom overlay scrollbars.

Real use · scrollable list panel

Both axes

Using Scroll Area

Silica ships one design system through three paths. They share a class vocabulary but are not interchangeable — pick the one that matches what you are building.

Plain HTML — CSS classes

The Tailwind v4 plugin. Works in any framework or none — Rails, Django, PHP, Go, a static file. This path ships no JavaScript, so Scroll Area is styled but inert: its behavior comes from scroll-area. For that behavior with no framework, use the node-tree path below.

/* in your CSS */
@import "tailwindcss";
@plugin "@wizeworks/silicaui";

Root class scroll-area, with 5 modifiers:

  • .scroll-area
  • .scroll-area-content
  • .scroll-area-corner
  • .scroll-area-scrollbar
  • .scroll-area-thumb
  • .scroll-area-viewport

React

Typed components over those same classes, with behavior and accessibility from Base UI.

npm i @wizeworks/silicaui-react
import { ScrollArea } from "@wizeworks/silicaui-react";

Props

PropTypeRequiredDescription
orientationScrollAreaOrientationnoWhich scrollbars to render. Default vertical.

Source of the demo above

The exact file that renders the examples above, so it can never drift from them. It imports a few of this site’s own layout helpers (../lib/…), so read it for the component calls rather than copying it whole.

Show source
import { ScrollArea } from "@wizeworks/silicaui-react";
import { Section, Row } from "../lib/Section";

const ITEMS = Array.from({ length: 30 }, (_, i) => `Item ${i + 1}`);

export function ScrollAreaDemo() {
    return (
        <>
            <Section title="Real use · scrollable list panel">
                <ScrollArea className="h-64 w-72 rounded-box border border-base-300">
                    <div className="flex flex-col gap-1 p-4">
                        {ITEMS.map((item) => (
                            <div key={item} className="rounded-field px-2 py-1 text-sm">
                                {item}
                            </div>
                        ))}
                    </div>
                </ScrollArea>
            </Section>

            <Section title="Both axes">
                <Row>
                    <ScrollArea
                        orientation="both"
                        className="h-48 w-64 rounded-box border border-base-300"
                    >
                        <div style={{ width: "40rem", height: "24rem" }} className="p-4">
                            Wide + tall content — scroll both directions.
                        </div>
                    </ScrollArea>
                </Row>
            </Section>
        </>
    );
}

Vanilla — node tree to HTML

scroll-area — a real overflow:auto track (CSS hides its native scrollbar) with a custom thumb the behavior sizes/positions from the viewport/content ratio — not achievable as a pure-CSS trick (confirmed this pass). Build a node tree, project it with toHtml(), and let the zero-dependency runtime hydrate it. This is the path for generated or user-authored documents — a site builder, CMS output, a static export.

npm i @wizeworks/silicaui-html @wizeworks/silicaui-behaviors
import { atom, toHtml } from "@wizeworks/silicaui-html";

const node = atom("ScrollArea", "scroll-area", { /* props */ }, [/* children */]);
const markup = toHtml(node);

Styling on this path is the class string in the second argument — the same classes as the Plain HTML section above. There is no color prop here; write "scroll-area scroll-area-primary" rather than passing a colour as a prop.

Takes children
yes
Hydrated by
scroll-area

Load @wizeworks/silicaui-behaviors on the page or this markup renders correctly and does nothing.

The full API for Scroll Area, on every path, is available through the Silica MCP server.