Scroll Area

Native overflow with styled scrollbars.

Native overflow with styled scrollbars. Use the default vertical direction or add horizontal scrolling for wide content.

Tags

v1.2.0-beta.50
v1.2.0-beta.49
v1.2.0-beta.48
v1.2.0-beta.47
v1.2.0-beta.46
v1.2.0-beta.45
v1.2.0-beta.44
v1.2.0-beta.43
v1.2.0-beta.42
v1.2.0-beta.41
v1.2.0-beta.40
v1.2.0-beta.39
v1.2.0-beta.38
v1.2.0-beta.37
v1.2.0-beta.36
v1.2.0-beta.35
v1.2.0-beta.34
v1.2.0-beta.33
v1.2.0-beta.32
v1.2.0-beta.31
v1.2.0-beta.30
v1.2.0-beta.29
v1.2.0-beta.28
v1.2.0-beta.27
v1.2.0-beta.26
v1.2.0-beta.25
v1.2.0-beta.24
v1.2.0-beta.23
v1.2.0-beta.22
v1.2.0-beta.21
v1.2.0-beta.20
v1.2.0-beta.19
v1.2.0-beta.18
v1.2.0-beta.17
v1.2.0-beta.16
v1.2.0-beta.15
v1.2.0-beta.14
v1.2.0-beta.13
v1.2.0-beta.12
v1.2.0-beta.11
v1.2.0-beta.10
v1.2.0-beta.9
v1.2.0-beta.8
v1.2.0-beta.7
v1.2.0-beta.6
v1.2.0-beta.5
v1.2.0-beta.4
v1.2.0-beta.3
v1.2.0-beta.2
v1.2.0-beta.1
tsx
import { Fragment } from "react"import { ScrollArea } from "@/components/ui/scroll-area"import { Separator } from "@/components/ui/separator"const tags = Array.from({ length: 50 }).map(  (_, i, a) => `v1.2.0-beta.${a.length - i}`,)export function Example() {  return (    <ScrollArea className="h-72 w-48 rounded-md border border-border">      <div className="p-4">        <h4 className="mb-4 text-sm font-medium tracking-wide text-foreground">          Tags        </h4>        {tags.map((tag, i) => (          <Fragment key={tag}>            <div className="text-sm font-normal tracking-wide text-foreground">              {tag}            </div>            {i < tags.length - 1 ? <Separator className="my-2" /> : null}          </Fragment>        ))}      </div>    </ScrollArea>  )}

Installation

npx @arctis-sh/@arctis-sh/ui@latest add scroll-area

Usage

import { ScrollArea } from "@/components/ui/scroll-area"
<ScrollArea className="h-[200px] w-[350px] rounded-md border border-border">  <div className="p-4">Scrollable content.</div></ScrollArea>

Composition

Vertical and horizontal scrollbars are included automatically.

ScrollArea
├── ScrollBar (vertical)
└── ScrollBar (horizontal)

Basic

A fixed-height area with a long list. Put padding on the content rather than the root.

Tags

v1.2.0-beta.50
v1.2.0-beta.49
v1.2.0-beta.48
v1.2.0-beta.47
v1.2.0-beta.46
v1.2.0-beta.45
v1.2.0-beta.44
v1.2.0-beta.43
v1.2.0-beta.42
v1.2.0-beta.41
v1.2.0-beta.40
v1.2.0-beta.39
v1.2.0-beta.38
v1.2.0-beta.37
v1.2.0-beta.36
v1.2.0-beta.35
v1.2.0-beta.34
v1.2.0-beta.33
v1.2.0-beta.32
v1.2.0-beta.31
v1.2.0-beta.30
v1.2.0-beta.29
v1.2.0-beta.28
v1.2.0-beta.27
v1.2.0-beta.26
v1.2.0-beta.25
v1.2.0-beta.24
v1.2.0-beta.23
v1.2.0-beta.22
v1.2.0-beta.21
v1.2.0-beta.20
v1.2.0-beta.19
v1.2.0-beta.18
v1.2.0-beta.17
v1.2.0-beta.16
v1.2.0-beta.15
v1.2.0-beta.14
v1.2.0-beta.13
v1.2.0-beta.12
v1.2.0-beta.11
v1.2.0-beta.10
v1.2.0-beta.9
v1.2.0-beta.8
v1.2.0-beta.7
v1.2.0-beta.6
v1.2.0-beta.5
v1.2.0-beta.4
v1.2.0-beta.3
v1.2.0-beta.2
v1.2.0-beta.1
tsx
import { Fragment } from "react"import { ScrollArea } from "@/components/ui/scroll-area"import { Separator } from "@/components/ui/separator"const tags = Array.from({ length: 50 }).map(  (_, i, a) => `v1.2.0-beta.${a.length - i}`,)export function Example() {  return (    <ScrollArea className="h-72 w-48 rounded-md border border-border">      <div className="p-4">        <h4 className="mb-4 text-sm font-medium tracking-wide text-foreground">          Tags        </h4>        {tags.map((tag, i) => (          <Fragment key={tag}>            <div className="text-sm font-normal tracking-wide text-foreground">              {tag}            </div>            {i < tags.length - 1 ? <Separator className="my-2" /> : null}          </Fragment>        ))}      </div>    </ScrollArea>  )}

Horizontal

Wide content reveals the horizontal scrollbar. Give the root a width and keep the row at w-max.

Attachment 1
Attachment 1
Attachment 2
Attachment 2
Attachment 3
Attachment 3
Attachment 4
Attachment 4
Attachment 5
Attachment 5
tsx
import { ScrollArea } from "@/components/ui/scroll-area"const works = [  {    label: "Attachment 1",    art: "/assets/brand/demos/attachments/attachment-1.png",  },  {    label: "Attachment 2",    art: "/assets/brand/demos/attachments/attachment-2.png",  },  {    label: "Attachment 3",    art: "/assets/brand/demos/attachments/attachment-3.png",  },  {    label: "Attachment 4",    art: "/assets/brand/demos/attachments/attachment-4.png",  },  {    label: "Attachment 5",    art: "/assets/brand/demos/attachments/attachment-5.png",  },]export function Example() {  return (    <ScrollArea className="w-96 whitespace-nowrap rounded-md border border-border">      <div className="flex w-max gap-4 p-4">        {works.map((work) => (          <figure key={work.label} className="shrink-0">            <div className="overflow-hidden rounded-md">              <img                src={work.art}                alt={work.label}                className="aspect-[3/4] h-fit w-[150px] object-cover"              />            </div>            <figcaption className="pt-2 text-xs font-normal tracking-wide text-muted-foreground">              {work.label}            </figcaption>          </figure>        ))}      </div>    </ScrollArea>  )}

API Reference

ScrollArea

The sized root contains the scroll viewport. Vertical and horizontal scrollbars appear only when content overflows.

PropTypeDefault
classNamestring
<ScrollArea className="h-48 w-64">  <div className="p-4">Long content…</div></ScrollArea>

ScrollBar

Rendered by ScrollArea when needed. Exported for the composition API.

PropTypeDefault
orientation"vertical" | "horizontal""vertical"
classNamestring
<ScrollBar orientation="vertical" />