Rime

ScrollArea, useScrollEdges and useScrollLock

The modal's scroll, made portable: thin tinted scrollbars, contained overscroll, edge shadows and a shared scroll lock.

ScrollArea wraps any scrolling region (a long list in a panel, long terms, a wide table with axis="x") and gives it the modal's scroll: thin native scrollbars in a brand tint (--scrollbar-thumb, --scrollbar-track, --scrollbar-width), overscroll-behavior: contain, and edge shadows that appear only when content has scrolled under the start edge or continues past the end (--scroll-edge-top, --scroll-edge-bottom, and -left/-right for x).

useScrollEdges(ref, { target, axis }) is the engine on its own: a passive scroll listener plus a ResizeObserver that toggle data-scrolled and data-more on the scroller (or a target such as a modal panel) without re-rendering React. Use it when your header and footer are siblings of the scroller and should cast the shadows themselves, as Modal does.

themedScrollClass is just the scrollbar and overscroll half, for a scroller you already have. useScrollLock() locks page scroll with a shared counter (nested overlays nest) and pays the scrollbar's width back as padding so nothing shifts.

Usage

import { ScrollArea, themedScrollClass, useScrollEdges, useScrollLock } from "@/components/ui";

<ScrollArea maxHeight={320} label="Workspace terms">
  {terms}
</ScrollArea>

Examples

Vertical

Scroll it: the top shade arrives once you leave the start; the bottom shade leaves at the end.
  • INV-1030 was paid
  • INV-1031 was sent to the customer
  • INV-1032 had a note added
  • INV-1033 was paid
  • INV-1034 was sent to the customer
  • INV-1035 had a note added
  • INV-1036 was paid
  • INV-1037 was sent to the customer
  • INV-1038 had a note added
  • INV-1039 was paid
  • INV-1040 was sent to the customer
  • INV-1041 had a note added
  • INV-1042 was paid
  • INV-1043 was sent to the customer

Horizontal (a wide table)

Sprint 1
Sprint 2
Sprint 3
Sprint 4
Sprint 5
Sprint 6
Sprint 7
Sprint 8
Sprint 9
Sprint 10
Sprint 11
Sprint 12

The hook on your own scroller

  • INV-1030 was paid
  • INV-1031 was sent to the customer
  • INV-1032 had a note added
  • INV-1033 was paid
  • INV-1034 was sent to the customer
  • INV-1035 had a note added
  • INV-1036 was paid
  • INV-1037 was sent to the customer
  • INV-1038 had a note added
  • INV-1039 was paid
  • INV-1040 was sent to the customer
  • INV-1041 had a note added
  • INV-1042 was paid
  • INV-1043 was sent to the customer

API

Generated from the component's TypeScript types and JSDoc (scripts/gen-ui-registry.mjs), so it always matches the source.

ScrollArea

ScrollArea props
PropTypeDefaultDescription
maxHeightCSSProperties["maxHeight"]Caps the viewport; the content scrolls past it. Any CSS length.
axis"y" | "x""y""y" (default) for lists and long copy, "x" for wide tables.
labelstringA name for the scrolling region. When set, the viewport joins the tab order (a keyboard user can scroll it) and is announced as a region.
childrenReactNode

Also accepts the native attributes of AriaAttributes, DOMAttributes, HTMLAttributes.

Theme tokens

Per-component tokens are undeclared by default, so the default shown is the fallback the CSS uses. Set one at :root (or in theme.css) to restyle every instance. Live values are read from this page, so they follow the Rime Studio.

This component has no tokens of its own; it reads the system tokens below.

System tokens it reads

ScrollArea, useScrollEdges and useScrollLock system tokens
TokenDefaultLive value
--dur-slowtokens.css…
--easetokens.css…
--focus-colortokens.css…
--scroll-edge-bottomtokens.css…
--scroll-edge-lefttokens.css…
--scroll-edge-righttokens.css…
--scroll-edge-toptokens.css…
--scrollbar-thumbtokens.css…
--scrollbar-tracktokens.css…
--scrollbar-widthtokens.css…

Accessibility

  • Pass label to make the region focusable (tabIndex 0) and named, so keyboard users can scroll it; skip it when the content already holds focusable items.
  • Native scrollbars stay: they keep platform behaviour (overlay scrollbars on macOS, high contrast in forced-colors).

Do and don't

Do

  • Use it for any region that scrolls inside the page.

Don't

  • Don't build a JavaScript scrollbar.
  • Don't nest two vertical scrollers.

For AI agents

This page as markdown, rendered from the same registry entry. Point an agent at it (or add .md to this page's URL), or at /llms.txt for the index.

Open scroll-area.md

Related: modal