

<Preview name="BasicScrollAreaExample" />

## Overview [#overview]

The `ScrollArea` component provides a scrollable viewport with custom scrollbars and optional edge shadows. It does not paint its own surface by default; put it inside the surface that owns the frame.

Scrollbar styling is surface-aware. Tracks land two levels above the current surface and thumbs land four levels above the current surface. Scroll shadows default to the current surface color, so a scroll area inside `Card` automatically fades to the card surface.

## Usage [#usage]

```tsx
import { Card } from "@tilt-legal/cubitt-components/card";
import {
  ScrollArea,
  ScrollAreaContent,
} from "@tilt-legal/cubitt-components/scroll-area";
```

```tsx
<Card className="h-72 w-56">
  <ScrollArea className="h-full w-full">
    <ScrollAreaContent className="p-4">
      {/* Scrollable content */}
    </ScrollAreaContent>
  </ScrollArea>
</Card>
```

## Examples [#examples]

### Basic [#basic]

A vertical scroll area inside a card. The card owns the surface and the scroll content owns the padding.

<Tabs items="['Preview', 'Code']">
  <Tab value="Preview">
    <Preview name="BasicScrollAreaExample" />
  </Tab>

  <Tab value="Code">
    ```tsx
    import { Card } from "@tilt-legal/cubitt-components/card";
    import {
      ScrollArea,
      ScrollAreaContent,
    } from "@tilt-legal/cubitt-components/scroll-area";
    import { Separator } from "@tilt-legal/cubitt-components/separator";

    export default function Example() {
      const tags = Array.from(
        { length: 50 },
        (_, index) => `v1.2.0-beta.${50 - index}`
      );

      return (
        <Card className="h-72 w-56">
          <ScrollArea className="h-full w-full">
            <ScrollAreaContent className="p-4">
              <h4 className="mb-4 font-medium text-sm leading-none">Tags</h4>
              {tags.map((tag) => (
                <div key={tag}>
                  <div className="text-sm">{tag}</div>
                  <Separator className="my-2" />
                </div>
              ))}
            </ScrollAreaContent>
          </ScrollArea>
        </Card>
      );
    }
    ```
  </Tab>
</Tabs>

### Horizontal [#horizontal]

Set `orientation="horizontal"` for horizontal overflow.

<Tabs items="['Preview', 'Code']">
  <Tab value="Preview">
    <Preview name="HorizontalScrollAreaExample" />
  </Tab>

  <Tab value="Code">
    ```tsx
    import type { CSSProperties } from "react";
    import { Card } from "@tilt-legal/cubitt-components/card";
    import {
      ScrollArea,
      ScrollAreaContent,
    } from "@tilt-legal/cubitt-components/scroll-area";

    const scrollbarInsetStyle = {
      "--scrollbar-inset-left": "1rem",
      "--scrollbar-inset-right": "1rem",
    } as CSSProperties;

    export default function Example() {
      const artworks = [
        { artist: "Ornella Binni" },
        { artist: "Tom Byrom" },
        { artist: "Vladimir Malyavko" },
      ];

      return (
        <Card className="h-52 w-full max-w-xl">
          <ScrollArea
            className="h-full w-full"
            orientation="horizontal"
            style={scrollbarInsetStyle}
          >
            <ScrollAreaContent className="flex w-max space-x-4 p-4">
              {artworks.map((artwork) => (
                <figure className="shrink-0" key={artwork.artist}>
                  <div className="h-36 w-48 rounded-lg bg-surface-5" />
                  <figcaption className="pt-2 text-fg-2 text-xs">
                    Photo by{" "}
                    <span className="font-semibold text-fg-1">
                      {artwork.artist}
                    </span>
                  </figcaption>
                </figure>
              ))}
            </ScrollAreaContent>
          </ScrollArea>
        </Card>
      );
    }
    ```
  </Tab>
</Tabs>

### Both Directions [#both-directions]

Set `orientation="both"` when content can overflow on both axes.

<Tabs items="['Preview', 'Code']">
  <Tab value="Preview">
    <Preview name="BothScrollAreaExample" />
  </Tab>

  <Tab value="Code">
    ```tsx
    import type { CSSProperties } from "react";
    import { Card } from "@tilt-legal/cubitt-components/card";
    import {
      ScrollArea,
      ScrollAreaContent,
    } from "@tilt-legal/cubitt-components/scroll-area";

    const scrollbarInsetStyle = {
      "--scrollbar-inset-left": "1rem",
      "--scrollbar-inset-right": "1rem",
    } as CSSProperties;

    export default function Example() {
      return (
        <Card className="h-72 w-full max-w-xl">
          <ScrollArea
            className="h-full w-full"
            orientation="both"
            style={scrollbarInsetStyle}
          >
            <ScrollAreaContent className="p-4">
              <div className="w-[600px] space-y-4">
                {Array.from({ length: 20 }).map((_, index) => (
                  <div className="flex gap-4" key={index}>
                    <div className="h-12 w-48 shrink-0 rounded-lg bg-surface-4" />
                    <div className="h-12 w-48 shrink-0 rounded-lg bg-surface-4" />
                    <div className="h-12 w-48 shrink-0 rounded-lg bg-surface-4" />
                  </div>
                ))}
              </div>
            </ScrollAreaContent>
          </ScrollArea>
        </Card>
      );
    }
    ```
  </Tab>
</Tabs>

### Scroll Shadows [#scroll-shadows]

Use `scrollShadow` to show edge gradients when more content is available.

<Tabs items="['Preview', 'Code']">
  <Tab value="Preview">
    <Preview name="BothShadowScrollAreaExample" />
  </Tab>

  <Tab value="Code">
    ```tsx
    import type { CSSProperties } from "react";
    import { Card } from "@tilt-legal/cubitt-components/card";
    import {
      ScrollArea,
      ScrollAreaContent,
    } from "@tilt-legal/cubitt-components/scroll-area";

    const scrollbarInsetStyle = {
      "--scrollbar-inset-left": "1rem",
      "--scrollbar-inset-right": "1rem",
    } as CSSProperties;

    export default function Example() {
      return (
        <Card className="h-72 w-full max-w-xl">
          <ScrollArea
            className="h-full w-full"
            orientation="both"
            scrollShadow="both"
            style={scrollbarInsetStyle}
          >
            <ScrollAreaContent className="p-4">
              {/* Wide and tall content */}
            </ScrollAreaContent>
          </ScrollArea>
        </Card>
      );
    }
    ```
  </Tab>
</Tabs>

### Custom Shadow [#custom-shadow]

Fine-tune shadow size, opacity, stop position, snap behavior, and color.

<Tabs items="['Preview', 'Code']">
  <Tab value="Preview">
    <Preview name="CustomShadowScrollAreaExample" />
  </Tab>

  <Tab value="Code">
    ```tsx
    import { Card } from "@tilt-legal/cubitt-components/card";
    import {
      ScrollArea,
      ScrollAreaContent,
    } from "@tilt-legal/cubitt-components/scroll-area";

    export default function Example() {
      return (
        <Card className="h-72 w-72">
          <ScrollArea
            className="h-full w-full"
            scrollShadow={{
              vertical: {
                size: "80px",
                stopPercent: 60,
                stopOpacity: 90,
                color: "var(--surface-3)",
              },
            }}
          >
            <ScrollAreaContent className="p-4">
              {/* Scrollable content */}
            </ScrollAreaContent>
          </ScrollArea>
        </Card>
      );
    }
    ```
  </Tab>
</Tabs>

## API Reference [#api-reference]

### ScrollArea [#scrollarea]

The root scrollable container component.

| Prop           | Type                                                                                 | Default      | Description                          |
| -------------- | ------------------------------------------------------------------------------------ | ------------ | ------------------------------------ |
| `orientation`  | `"vertical"` \| `"horizontal"` \| `"both"`                                           | `"vertical"` | Direction of scrolling.              |
| `scrollShadow` | `"vertical"` \| `"horizontal"` \| `"both"` \| `"none"` \| `ScrollShadowObjectConfig` | `"none"`     | Optional edge shadow configuration.  |
| `className`    | `string`                                                                             | —            | Additional classes for the viewport. |

### ScrollShadowConfig [#scrollshadowconfig]

| Property      | Type      | Default         | Description                                                              |
| ------------- | --------- | --------------- | ------------------------------------------------------------------------ |
| `size`        | `string`  | `"40px"`        | Size of the shadow gradient.                                             |
| `color`       | `string`  | Current surface | CSS color used for the gradient.                                         |
| `stopPercent` | `number`  | `0`             | Percentage where the solid color ends and fading begins.                 |
| `stopOpacity` | `number`  | `100`           | Opacity of the intermediate color stop before fading to transparent.     |
| `snap`        | `boolean` | `false`         | When true, the shadow appears at full size instead of growing gradually. |

### ScrollShadowObjectConfig [#scrollshadowobjectconfig]

The object configuration supports axis shortcuts or individual sides. Do not mix an axis shortcut with that axis' side-specific keys.

| Property     | Type                              | Description                                     |
| ------------ | --------------------------------- | ----------------------------------------------- |
| `vertical`   | `boolean` \| `ScrollShadowConfig` | Shortcut for top and bottom shadows.            |
| `horizontal` | `boolean` \| `ScrollShadowConfig` | Shortcut for left and right shadows.            |
| `top`        | `boolean` \| `ScrollShadowConfig` | Top shadow. Cannot be used with `vertical`.     |
| `bottom`     | `boolean` \| `ScrollShadowConfig` | Bottom shadow. Cannot be used with `vertical`.  |
| `left`       | `boolean` \| `ScrollShadowConfig` | Left shadow. Cannot be used with `horizontal`.  |
| `right`      | `boolean` \| `ScrollShadowConfig` | Right shadow. Cannot be used with `horizontal`. |

### ScrollAreaContent [#scrollareacontent]

Container for the scrollable content.

| Prop        | Type     | Default | Description                                   |
| ----------- | -------- | ------- | --------------------------------------------- |
| `className` | `string` | —       | Additional classes for the content container. |

### ScrollBar [#scrollbar]

Custom scrollbar component used internally by `ScrollArea`.

| Prop          | Type                           | Default      | Description                       |
| ------------- | ------------------------------ | ------------ | --------------------------------- |
| `orientation` | `"vertical"` \| `"horizontal"` | `"vertical"` | Direction of the scrollbar.       |
| `className`   | `string`                       | —            | Additional classes for the track. |

### CSS Custom Properties [#css-custom-properties]

Scrollbar inset variables are orientation-specific. Vertical scrollbars read the top and bottom variables; horizontal scrollbars read the left and right variables.

| Variable                   | Default | Description                                      |
| -------------------------- | ------- | ------------------------------------------------ |
| `--scrollbar-inset-top`    | `1rem`  | Top inset used by vertical scrollbar tracks.     |
| `--scrollbar-inset-bottom` | `1rem`  | Bottom inset used by vertical scrollbar tracks.  |
| `--scrollbar-inset-left`   | `0rem`  | Left inset used by horizontal scrollbar tracks.  |
| `--scrollbar-inset-right`  | `0rem`  | Right inset used by horizontal scrollbar tracks. |
