Skip to content
HyperDesign System

Scroll area

A scroll container with a slim 40% tint thumb that reads on both canvases, in place of the browser's scrollbar inside small panels. Native scrolling, keyboard and touch are kept. Source: src/components/ui/scroll-area.tsx.

Vertical

Give the root a fixed height. The thumb appears on hover and while scrolling; scroll the list to see it.

Channels

#announcements

#design

#design-crit

#eng

#eng-oncall

#eng-updates

#growth

#incidents

#infra

#launches

#product

#random

#sales

#support

Horizontal

ScrollArea always mounts a vertical bar. For a sideways row, put a ScrollBar orientation="horizontal" inside the children and give the row w-max.

Mon 21
Tue 22
Wed 23
Thu 24
Fri 25
Sat 26
Sun 27
Mon 28
Tue 29
Wed 30

Reaching the viewport

viewportRef and viewportProps expose the element that actually scrolls. Here onScroll drives a readout and the button scrolls to the end, as the thread view does.

  1. 09:12fetch_issues · 18 results
  2. 09:13read_file · src/app/page.tsx
  3. 09:14search · "rate limit"
  4. 09:15summarise · 3 threads
  5. 09:16write_comment · LIN-482
  6. 09:17run_tests · 212 passed
  7. 09:18fetch_issues · 18 results
  8. 09:19read_file · src/app/page.tsx
  9. 09:20search · "rate limit"
  10. 09:21summarise · 3 threads
  11. 09:22write_comment · LIN-482
  12. 09:23run_tests · 212 passed
  13. 09:24fetch_issues · 18 results
  14. 09:25read_file · src/app/page.tsx
  15. 09:26search · "rate limit"
  16. 09:27summarise · 3 threads
  17. 09:28write_comment · LIN-482
  18. 09:29run_tests · 212 passed
  19. 09:30fetch_issues · 18 results
  20. 09:31read_file · src/app/page.tsx
  21. 09:32search · "rate limit"
  22. 09:33summarise · 3 threads
  23. 09:34write_comment · LIN-482
  24. 09:35run_tests · 212 passed
0% scrolled

Props

Scroll area props
PropTypeDefaultDescription
viewportRefRef<HTMLDivElement>—ScrollArea. A ref to the scrolling viewport, for measuring or scrollTo.
viewportPropsComponentProps<typeof ScrollArea.Viewport>—ScrollArea. Spread onto the viewport: onScroll, tabIndex, aria-*, and a className merged after the primitive's.
type"hover" | "scroll" | "auto" | "always""hover"ScrollArea (Radix). When the bar shows: on hover, while scrolling, on overflow, or always.
orientation"vertical" | "horizontal""vertical"ScrollBar. ScrollArea mounts a vertical bar itself; add a horizontal one as a child.
...propsComponentProps<typeof ScrollArea.Root>—Native attributes pass through; className merges last. Give the root a height (or max-h) so it can overflow.

Best practices

When to use

  • Small, bounded panels inside a page: a list in a popover, a log, a sidebar section.
  • Never for the page itself. The document scrolls with the browser's own bar.

Behavior

  • The root needs a height or max-height; without one it grows with its content and never scrolls.
  • Hint at more content: let the last row be cut off by the edge rather than ending flush.
  • Respect reduced motion when you scroll programmatically: use behavior "auto" instead of "smooth".

Accessibility

  • If nothing inside is focusable, pass tabIndex: 0 and an aria-label through viewportProps so keyboard users can scroll it. The viewport shows the focus ring.
  • Don't trap content that matters only behind a scroll; key actions stay outside the scroller.

Content

  • Lists, logs and rows. Long prose reads better at full height on the page.