Scroll Area

A scrollable region with custom, consistently styled scrollbars that keep native scrolling behavior.

Default

ScrollArea lets you control the appearance of scrollbars in a scrollable region.

Tags
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 { ScrollArea } from "@hummingbirdui/react";

const tags = Array.from({ length: 30 }, (_, i) => `v1.2.0-beta.${30 - i}`);

export default function ScrollAreaDefault() {
  return (
    <ScrollArea className="mx-auto h-72 w-48 rounded-lg border border-subtle">
      <ScrollArea.Viewport className="p-4">
        <h6 className="mb-2 text-sm font-semibold">Tags</h6>
        {tags.map((tag) => (
          <div key={tag} className="border-b border-subtle py-2 text-sm">
            {tag}
          </div>
        ))}
      </ScrollArea.Viewport>
      <ScrollArea.Scrollbar />
    </ScrollArea>
  );
}

Horizontal

Use orientation="horizontal" on the scrollbar to handle horizontally overflowing content.

Photo by Vladimir Malyavko
Photo by Vladimir Malyavko
Photo by Bailey Zindel
Photo by Bailey Zindel
Photo by Pablo Heimplatz
Photo by Pablo Heimplatz
Photo by Ornella Binni
Photo by Ornella Binni
Photo by Tom Byrom
Photo by Tom Byrom

tsx

import { ScrollArea } from "@hummingbirdui/react";

const artworks = [
  {
    artist: "Vladimir Malyavko",
    art: "https://images.unsplash.com/photo-1494337480532-3725c85fd2ab?q=80&w=600&auto=format&fit=crop",
  },
  {
    artist: "Bailey Zindel",
    art: "https://images.unsplash.com/photo-1469474968028-56623f02e42e?q=80&w=600&auto=format&fit=crop",
  },
  {
    artist: "Pablo Heimplatz",
    art: "https://images.unsplash.com/photo-1494256997604-768d1f608cac?q=80&w=600&auto=format&fit=crop",
  },
  {
    artist: "Ornella Binni",
    art: "https://images.unsplash.com/photo-1465869185982-5a1a7522cbcb?q=80&w=600&auto=format&fit=crop",
  },
  {
    artist: "Tom Byrom",
    art: "https://images.unsplash.com/photo-1548516173-3cabfa4607e9?q=80&w=600&auto=format&fit=crop",
  },
];

export default function ScrollAreaHorizontal() {
  return (
    <ScrollArea className="mx-auto w-96 max-w-full rounded-lg border border-subtle">
      <ScrollArea.Viewport>
        <div className="flex gap-4 p-4">
          {artworks.map(({ artist, art }) => (
            <figure key={artist} className="shrink-0">
              <div className="overflow-hidden rounded-lg">
                <img
                  src={art}
                  alt={`Photo by ${artist}`}
                  className="aspect-3/4 h-80 w-auto object-cover"
                />
              </div>
              <figcaption className="pt-2 text-xs text-muted">
                Photo by{" "}
                <span className="font-semibold text-default">{artist}</span>
              </figcaption>
            </figure>
          ))}
        </div>
      </ScrollArea.Viewport>
      <ScrollArea.Scrollbar orientation="horizontal" rounded />
    </ScrollArea>
  );
}

Both directions

#NameEmailRoleStatus
1Person 1person1@example.comMemberActive
2Person 2person2@example.comMemberActive
3Person 3person3@example.comMemberActive
4Person 4person4@example.comMemberActive
5Person 5person5@example.comMemberActive
6Person 6person6@example.comMemberActive
7Person 7person7@example.comMemberActive
8Person 8person8@example.comMemberActive
9Person 9person9@example.comMemberActive
10Person 10person10@example.comMemberActive
11Person 11person11@example.comMemberActive
12Person 12person12@example.comMemberActive
13Person 13person13@example.comMemberActive
14Person 14person14@example.comMemberActive
15Person 15person15@example.comMemberActive
16Person 16person16@example.comMemberActive
17Person 17person17@example.comMemberActive
18Person 18person18@example.comMemberActive
19Person 19person19@example.comMemberActive
20Person 20person20@example.comMemberActive

tsx

import { ScrollArea, Table } from "@hummingbirdui/react";

const rows = Array.from({ length: 20 }, (_, i) => i + 1);

export default function ScrollAreaBoth() {
  return (
    <ScrollArea className="mx-auto h-72 w-96 max-w-full rounded-lg border border-subtle">
      <ScrollArea.Viewport>
        <Table className="w-[40rem]">
          <thead>
            <tr>
              <th>#</th>
              <th>Name</th>
              <th>Email</th>
              <th>Role</th>
              <th>Status</th>
            </tr>
          </thead>
          <tbody>
            {rows.map((row) => (
              <tr key={row}>
                <td>{row}</td>
                <td>Person {row}</td>
                <td>person{row}@example.com</td>
                <td>Member</td>
                <td>Active</td>
              </tr>
            ))}
          </tbody>
        </Table>
      </ScrollArea.Viewport>
      <ScrollArea.Scrollbar />
      <ScrollArea.Scrollbar orientation="horizontal" />
      <ScrollArea.Corner />
    </ScrollArea>
  );
}

Rounded

Use rounded prop on the scrollbar to round the scrollbar track and thumb.

The rounded scrollbar keeps the pill-shaped track and thumb from Hummingbird's scrollbar-rounded utility. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Integer nec odio. Praesent libero. Sed cursus ante dapibus diam. Sed nisi. Nulla quis sem at nibh elementum imperdiet. Duis sagittis ipsum. Praesent mauris. Fusce nec tellus sed augue semper porta. Mauris massa. Vestibulum lacinia arcu eget nulla. Curabitur sodales ligula in libero. Sed dignissim lacinia nunc. Curabitur tortor. Pellentesque nibh. Aenean quam. In scelerisque sem at dolor. Maecenas mattis. Sed convallis tristique sem. Proin ut ligula vel nunc egestas porttitor. Morbi lectus risus, iaculis vel, suscipit quis, luctus non, massa.

tsx

import { ScrollArea } from "@hummingbirdui/react";

export default function ScrollAreaRounded() {
  return (
    <ScrollArea
      type="always"
      className="mx-auto h-72 w-64 rounded-lg border border-subtle"
    >
      <ScrollArea.Viewport className="p-4 pe-6">
        <p className="text-sm">
          The rounded scrollbar keeps the pill-shaped track and thumb from
          Hummingbird&apos;s <code>scrollbar-rounded</code> utility. Lorem ipsum
          dolor sit amet, consectetur adipiscing elit. Integer nec odio.
          Praesent libero. Sed cursus ante dapibus diam. Sed nisi. Nulla quis
          sem at nibh elementum imperdiet. Duis sagittis ipsum. Praesent mauris.
          Fusce nec tellus sed augue semper porta. Mauris massa. Vestibulum
          lacinia arcu eget nulla. Curabitur sodales ligula in libero. Sed
          dignissim lacinia nunc. Curabitur tortor. Pellentesque nibh. Aenean
          quam. In scelerisque sem at dolor. Maecenas mattis. Sed convallis
          tristique sem. Proin ut ligula vel nunc egestas porttitor. Morbi
          lectus risus, iaculis vel, suscipit quis, luctus non, massa.
        </p>
      </ScrollArea.Viewport>
      <ScrollArea.Scrollbar rounded />
    </ScrollArea>
  );
}

Always visible

Use type="always" on the scrollbar to keep the scrollbar visible whenever content overflows, instead of showing it on hover.

With type="always" the scrollbar stays visible whenever the content overflows, instead of appearing on hover. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Integer nec odio. Praesent libero. Sed cursus ante dapibus diam. Sed nisi. Nulla quis sem at nibh elementum imperdiet. Duis sagittis ipsum. Praesent mauris. Fusce nec tellus sed augue semper porta. Mauris massa. Vestibulum lacinia arcu eget nulla. Curabitur sodales ligula in libero. Sed dignissim lacinia nunc. Curabitur tortor. Pellentesque nibh. Aenean quam. In scelerisque sem at dolor. Maecenas mattis. Sed convallis tristique sem. Proin ut ligula vel nunc egestas porttitor.

tsx

import { ScrollArea } from "@hummingbirdui/react";

export default function ScrollAreaAlways() {
  return (
    <ScrollArea
      type="always"
      className="mx-auto h-72 w-64 rounded-lg border border-subtle"
    >
      <ScrollArea.Viewport className="p-4 pe-6">
        <p className="text-sm">
          With <code>type=&quot;always&quot;</code> the scrollbar stays visible
          whenever the content overflows, instead of appearing on hover. Lorem
          ipsum dolor sit amet, consectetur adipiscing elit. Integer nec odio.
          Praesent libero. Sed cursus ante dapibus diam. Sed nisi. Nulla quis
          sem at nibh elementum imperdiet. Duis sagittis ipsum. Praesent mauris.
          Fusce nec tellus sed augue semper porta. Mauris massa. Vestibulum
          lacinia arcu eget nulla. Curabitur sodales ligula in libero. Sed
          dignissim lacinia nunc. Curabitur tortor. Pellentesque nibh. Aenean
          quam. In scelerisque sem at dolor. Maecenas mattis. Sed convallis
          tristique sem. Proin ut ligula vel nunc egestas porttitor.
        </p>
      </ScrollArea.Viewport>
      <ScrollArea.Scrollbar />
    </ScrollArea>
  );
}

API Reference

ScrollArea is built on the Radix UI Scroll Area primitive. Each part forwards all props to its Radix counterpart.

ScrollArea

PropTypeDefault
asChildbooleanfalse
typeenum"hover"
scrollHideDelaynumber600
direnum
noncestring
classNamestring

ScrollArea.Viewport

PropTypeDefault
asChildbooleanfalse
classNamestring

ScrollArea.Scrollbar

PropTypeDefault
asChildbooleanfalse
orientationenum"vertical"
roundedbooleanfalse
forceMountboolean
classNamestring

Data attributeValues
[data-state]visible | hidden
[data-orientation]vertical | horizontal

ScrollArea.Thumb

PropTypeDefault
asChildbooleanfalse
forceMountboolean
classNamestring

Data attributeValues
[data-state]visible | hidden

ScrollArea.Corner

PropTypeDefault
asChildbooleanfalse
classNamestring

Styling

The scroll area component utilizes several CSS variables for customization, defined on the root's scroll-area class. Overriding them restyles the scrollbar size, track, and thumb.

.scroll-area {
  --scroll-area-scrollbar-size: --spacing(3);
  --scroll-area-thumb-color: var(--background-color-emphasis);
  --scroll-area-track-color: var(--background-color-muted);
}