Skip to content
LayoutGenerated from the public API

ScrollArea

A styled scroll container that keeps the platform's scrolling semantics.

@luc/ui

Examples

Vertical scrolling

A region that scrolls with a scrollbar the design system owns: one width, thumb and corner on every platform, sitting beside the content instead of over the last row.

Instruments

24

Instrument 01

0.37

Instrument 02

0.74

Instrument 03

1.10

Instrument 04

1.48

Instrument 05

1.85

Instrument 06

2.21

Instrument 07

2.59

Instrument 08

2.96

Instrument 09

3.33

Instrument 10

3.7%

Instrument 11

4.07

Instrument 12

4.43

Instrument 13

4.81

Instrument 14

5.18

Instrument 15

5.55

Instrument 16

5.92

Instrument 17

6.29

Instrument 18

6.66

Instrument 19

7.03

Instrument 20

7.4%

Instrument 21

7.77

Instrument 22

8.14

Instrument 23

8.51

Instrument 24

8.87

Horizontal scrolling

`viewportClassName` is where the content's own padding and layout live. A wide table scrolls inside its box instead of widening the page — which is why this component sits under the DataTable. Shown with `type="always"` so the bar is visible in a screenshot; the default is `hover`.

C1

C2

C3

C4

C5

C6

C7

C8

C9

C10

C11

C12

Both axes

A region that is too wide *and* too tall gets two scrollbars and the corner that keeps them from overlapping — the case a bare `overflow-auto` box gets subtly wrong on every platform.

R1

R2

R3

R4

R5

R6

R7

R8

R9

R10

R11

R12

R13

R14

R15

R16

R17

R18

R19

R20

R21

R22

R23

R24

R25

R26

R27

R28

R29

R30

R31

R32

R33

R34

R35

R36

R37

R38

R39

R40

R41

R42

R43

R44

R45

R46

R47

R48

Scrollbar policy

`type` decides when the scrollbar is visible: `hover` keeps it present but quiet, `always` reserves it so the there-is-more cue is there without touching the region.

Row 1

Row 2

Row 3

Row 4

Row 5

Row 6

Row 7

Row 8

Row 9

Row 10

type=hover

Row 1

Row 2

Row 3

Row 4

Row 5

Row 6

Row 7

Row 8

Row 9

Row 10

type=always

Long content

What makes a scroll region worth naming: content long enough to scroll, a last row that is reachable, and the region itself a tab stop so a keyboard reader can reach it without a pointer.

Research notes

1 The region keeps its height whatever the copy is.

2 The region keeps its height whatever the copy is.

3 The region keeps its height whatever the copy is.

4 The region keeps its height whatever the copy is.

5 The region keeps its height whatever the copy is.

6 The region keeps its height whatever the copy is.

Usage

import { ScrollArea } from "@luc/ui";
<ScrollArea className="h-64" viewportClassName="p-3">
  …
</ScrollArea>

Give the region a definite height, and put the content's own padding on `viewportClassName` so it scrolls with the content.

Package setup — peer requirements, the stylesheet and the provider — is on installation.

API

Read from the published TypeScript API, so a prop that is not listed here does not exist and a default that is listed is the one the compiler sees.

Exported symbols
ExportKindSignature
ScrollArea8 documented props({ className, viewportClassName, type, scrollbarSize, corner, children, ...props }: ScrollAreaProps) => import("@types/react").JSX.Element
ScrollAreaRoot4 documented propsimport("@types/react").ForwardRefExoticComponent<RadixScrollArea.ScrollAreaProps & import("@types/react").RefAttributes<HTMLDivElement>>

ScrollArea props

Type: ScrollAreaProps

Values the compiler reads from the declaration.

ScrollArea props
PropTypeDefaultNotes
asChild?inheritedboolean | undefined—
children?ReactNode—
corner?boolean | undefined—Render the corner filler between the two scrollbars. Default `true`.
dir?inheritedDirection | undefined—
scrollbarSize?number | undefined—Fixed size for both scrollbars, in px.
scrollHideDelay?inheritednumber | undefined—
type?"auto" | "always" | "hover" | "scroll" | undefined—Scrollbar visibility policy. `hover` is the default — present, not loud.
viewportClassName?string | undefined—Viewport class. Height, padding and layout belong here.

ScrollAreaRoot props

Type: ScrollAreaProps & RefAttributes<HTMLDivElement>

Values the compiler reads from the declaration.

ScrollAreaRoot props
PropTypeDefaultNotes
asChild?inheritedboolean | undefined—
dir?inheritedDirection | undefined—
scrollHideDelay?inheritednumber | undefined—
type?inherited"auto" | "always" | "hover" | "scroll" | undefined—

Guidelines

Do

  • Give the region a definite size or a definite parent: a scroll area with no height constraint simply grows, and the reader gets the page's scrollbar instead of the component's.
  • Pass the content's padding and layout through `viewportClassName`, so the padding scrolls with the content and the scrollbar does not land on top of it.
  • Use it for a long list, a wide table or a code block inside a fixed-height panel — the cases where a platform scrollbar's width would shift the layout.

Don't

  • Do not nest two scroll areas on the same axis: nested vertical scrolling traps a trackpad and a keyboard alike.
  • Do not hide the scrollbar to make a region prettier — `type="hover"` keeps the cue, and `type="always"` is for a reader who has to know there is more.
  • Do not use it as a page container: the page already scrolls, and a second scrollbar costs the reader their position in it.

Accessibility

The viewport is a tab stop with a visible focus ring, because a keyboard user cannot drag a scrollbar and the content has to be reachable without a pointer. The scrollbars themselves are decorative in the accessibility tree, so nothing is announced twice — and content below the fold is still in the DOM, so it is still read and still searchable.

Family

Layout

Space, rhythm and the surfaces a page is made of.

10 documented entries in this family. Open the family index

Luc UI v1.0ScrollAreadark theme