# Scroll Area

A scroll container with overlay scrollbars and automatic edge fades.

## Installation

```bash
npx shadcn@latest add https://ui.jarv.is/r/scroll-area.json
```

[Registry JSON](https://ui.jarv.is/r/scroll-area.json)

## Preview

```tsx
import { ScrollArea } from "@/components/ui/scroll-area";

export function Preview() {
  const activity = [
    "Renewed domainstack.io",
    "Queued DNS audit",
    "Pinned registrar notes",
    "Updated MX records",
    "Synced billing contact",
    "Archived expired domains",
    "Reviewed transfer lock",
    "Checked nameserver drift",
    "Scheduled renewal reminder",
    "Exported portfolio report",
  ];

  return (
    <ScrollArea className="h-56 w-full max-w-sm rounded-lg border bg-card" scrollbarGutter>
      <div className="flex flex-col gap-3 p-4">
        {activity.map((item, index) => (
          <div key={item} className="flex items-center justify-between gap-4 text-sm">
            <span>{item}</span>
            <span className="shrink-0 text-muted-foreground">#{index + 1}</span>
          </div>
        ))}
      </div>
    </ScrollArea>
  );
}
```


## Source

### ui/scroll-area.tsx

```tsx
"use client";

import { ScrollArea as ScrollAreaPrimitive } from "@base-ui/react/scroll-area";
import type * as React from "react";

import { cn } from "@/lib/utils";

type ScrollAreaProps = ScrollAreaPrimitive.Root.Props & {
  scrollFade?: boolean;
  scrollbarGutter?: boolean;
  hideScrollbar?: boolean;
  scrollRef?: React.Ref<HTMLDivElement>;
  contentRef?: React.Ref<HTMLDivElement>;
};

function ScrollArea({
  className,
  children,
  scrollFade = true,
  scrollbarGutter = false,
  hideScrollbar = false,
  scrollRef,
  contentRef,
  ...props
}: ScrollAreaProps) {
  return (
    <ScrollAreaPrimitive.Root
      data-slot="scroll-area"
      className={cn("relative flex min-h-0 min-w-0 overflow-hidden", className)}
      {...props}
    >
      <ScrollAreaPrimitive.Viewport
        data-slot="scroll-area-viewport"
        ref={scrollRef}
        className={cn(
          "flex-1 rounded-[inherit] outline-none [scrollbar-width:none] focus-visible:ring-3 focus-visible:ring-ring/50 focus-visible:outline-1 data-has-overflow-x:overscroll-x-contain [&::-webkit-scrollbar]:hidden",
          scrollFade &&
            "mask-t-from-[calc(100%-min(var(--fade-size),var(--scroll-area-overflow-y-start)))] mask-r-from-[calc(100%-min(var(--fade-size),var(--scroll-area-overflow-x-end)))] mask-b-from-[calc(100%-min(var(--fade-size),var(--scroll-area-overflow-y-end)))] mask-l-from-[calc(100%-min(var(--fade-size),var(--scroll-area-overflow-x-start)))] [--fade-size:1.5rem]",
          scrollbarGutter && "data-has-overflow-x:pb-2.5 data-has-overflow-y:pr-2.5",
        )}
      >
        <ScrollAreaPrimitive.Content data-slot="scroll-area-content" ref={contentRef}>
          {children}
        </ScrollAreaPrimitive.Content>
      </ScrollAreaPrimitive.Viewport>
      {!hideScrollbar && (
        <>
          <ScrollBar orientation="vertical" />
          <ScrollBar orientation="horizontal" />
        </>
      )}
      <ScrollAreaPrimitive.Corner data-slot="scroll-area-corner" />
    </ScrollAreaPrimitive.Root>
  );
}

function ScrollBar({
  className,
  orientation = "vertical",
  ...props
}: ScrollAreaPrimitive.Scrollbar.Props) {
  return (
    <ScrollAreaPrimitive.Scrollbar
      data-slot="scroll-area-scrollbar"
      orientation={orientation}
      className={cn(
        "m-1 flex opacity-0 transition-opacity delay-300 data-hovering:opacity-100 data-hovering:delay-0 data-hovering:duration-100 data-scrolling:opacity-100 data-scrolling:delay-0 data-scrolling:duration-100 data-[orientation=horizontal]:h-1 data-[orientation=horizontal]:flex-col data-[orientation=vertical]:w-1",
        className,
      )}
      {...props}
    >
      <ScrollAreaPrimitive.Thumb
        data-slot="scroll-area-thumb"
        className="relative flex-1 rounded-full bg-foreground/40"
      />
    </ScrollAreaPrimitive.Scrollbar>
  );
}

export { ScrollArea, ScrollBar };
```



## Usage

### Basic viewport

Use the scroll area when content needs a compact viewport with subtle edge fades and overlay
scrollbars.

```tsx
import { ScrollArea } from "@/components/ui/scroll-area";

export function Example() {
  return <ScrollArea className="h-48">...</ScrollArea>;
}
```

### Lists and sidebars

Give the root a fixed height and put normal block content inside.

```tsx
import { ScrollArea } from "@/components/ui/scroll-area";

export function ActivityList({ items }: { items: string[] }) {
  return (
    <ScrollArea className="h-64 rounded-lg border" scrollbarGutter>
      <div className="space-y-3 p-4">
        {items.map((item) => (
          <div key={item} className="text-sm">
            {item}
          </div>
        ))}
      </div>
    </ScrollArea>
  );
}
```

### Horizontal overflow

Use it for long single-line content too. The edge fade works on both axes.

```tsx
import { ScrollArea } from "@/components/ui/scroll-area";

export function CommandStrip() {
  return (
    <ScrollArea className="w-80 rounded-md border" scrollbarGutter>
      <pre className="p-3 text-sm">
        bunx --bun shadcn@latest add https://ui.jarv.is/r/scroll-area.json
      </pre>
    </ScrollArea>
  );
}
```

### Disable chrome

Turn off fades or scrollbars when another surface already supplies that affordance.

```tsx
import type { ReactNode } from "react";

import { ScrollArea } from "@/components/ui/scroll-area";

export function PlainScrollablePanel({ children }: { children: ReactNode }) {
  return (
    <ScrollArea className="h-72" scrollFade={false} hideScrollbar>
      {children}
    </ScrollArea>
  );
}
```

### Access scroll nodes

Use refs when you need imperative scroll restoration or measurement.

```tsx
import { useRef } from "react";

import { ScrollArea } from "@/components/ui/scroll-area";

export function RestorableLog({ entries }: { entries: string[] }) {
  const scrollRef = useRef<HTMLDivElement>(null);

  return (
    <ScrollArea className="h-72" scrollRef={scrollRef}>
      {entries.map((entry) => (
        <p key={entry}>{entry}</p>
      ))}
    </ScrollArea>
  );
}
```

