# ScrollArea

> A native scroll container with thin themed scrollbars, edge fades and keyboard access.

Category: Advanced · Status: stable · Package: @bindshq/stance-react@0.1.1 · Docs: https://stanceui.com/components/scroll-area

Use ScrollArea for bounded regions that scroll independently, such as an activity feed, a long legal disclaimer or a row of template thumbnails. It uses the browser’s real scrolling, so wheel, touch, keyboard and assistive technology all behave natively. When content overflows it becomes a focusable, labelled region.

## Import

```tsx
import { ScrollArea } from '@bindshq/stance-react';
```

Styles are imported once per app: `@bindshq/stance-tokens/css` and `@bindshq/stance-react/styles.css`.

## Examples

### Vertical

```tsx
import { ScrollArea } from '@bindshq/stance-react';

const activity = [
  'Priya Nair deployed the Sales team signature to 12 mailboxes',
  'Amara Okafor updated the legal disclaimer',
  'Exchange relay synced 48 mailboxes',
  'Lukas Brenner joined the organisation',
  'Hana Sato approved the Finance template',
  'Tomás Ruiz requested access to Integrations',
  'Owen Price created the Q4 summit banner',
  'Zainab Haddad archived the Holiday template',
  'Mateja Kovač connected Azure AD',
  'Rollout completed for Customer Success',
];

export function Basic() {
  return (
    <div
      style={{
        maxWidth: 420,
        border: '1px solid var(--st-color-border-default)',
        borderRadius: 12,
      }}
    >
      <ScrollArea label="Recent activity" maxHeight={200}>
        <ul style={{ margin: 0, padding: '8px 16px' }}>
          {activity.map((a) => (
            <li key={a} style={{ padding: '8px 0' }}>
              {a}
            </li>
          ))}
        </ul>
      </ScrollArea>
    </div>
  );
}
```

### Horizontal

```tsx
import { ScrollArea } from '@bindshq/stance-react';

export function Horizontal() {
  return (
    <ScrollArea label="Signature templates" orientation="horizontal" style={{ maxWidth: 520 }}>
      <div style={{ display: 'flex', gap: 12, padding: 4, width: 'max-content' }}>
        {[
          'Standard',
          'Sales team',
          'Legal',
          'Recruiting',
          'Q4 summit',
          'Holiday',
          'Support',
          'Partners',
        ].map((t) => (
          <div
            key={t}
            style={{
              width: 140,
              height: 90,
              padding: 12,
              borderRadius: 10,
              border: '1px solid var(--st-color-border-default)',
              background: 'var(--st-color-bg-subtle)',
            }}
          >
            {t}
          </div>
        ))}
      </div>
    </ScrollArea>
  );
}
```

### Without fades

Edge fades are removed automatically in high contrast mode.

```tsx
import { ScrollArea } from '@bindshq/stance-react';

export function NoFade() {
  return (
    <ScrollArea label="Legal disclaimer" maxHeight={140} fade={false} style={{ maxWidth: 480 }}>
      <p style={{ margin: 0 }}>
        This email and any attachments are confidential and intended solely for the addressee. If
        you have received it in error, please notify the sender and delete it. Binds d.o.o. accepts
        no liability for changes made to this message after it was sent. Opinions expressed are
        those of the author and do not necessarily represent Binds. Our privacy notice explains how
        we process personal data in correspondence and is available at binds.si/privacy.
      </p>
    </ScrollArea>
  );
}
```

## API reference

| Component | Prop | Type | Default | Description |
| --- | --- | --- | --- | --- |
| ScrollArea | `label` | `string` | None | Accessible label. Required for the region to be announced when it overflows. |
| ScrollArea | `orientation` | `'vertical' \| 'horizontal' \| 'both'` | `'vertical'` | Scroll axis. |
| ScrollArea | `maxHeight` | `number \| string` | None | Maximum height before vertical scrolling. |
| ScrollArea | `height` | `number \| string` | None | Fixed height. |
| ScrollArea | `maxWidth` | `number \| string` | None | Maximum width before horizontal scrolling. |
| ScrollArea | `fade` | `boolean` | `true` | Fade content at edges that have more to scroll. |
| ScrollArea | `scrollbar` | `'thin' \| 'auto'` | `'thin'` | Scrollbar thickness. |

## Accessibility

- When content overflows, the area gets tabindex="0" and role="region" with your label, so keyboard users can focus it and scroll with the arrow keys (WCAG 2.1.1).
- When content fits, the area stays out of the tab order.
- Scrollbars are native, so platform settings such as “always show scrollbars” are respected.
- Edge fades are disabled in high contrast mode and under prefers-contrast: more.

## Keyboard

| Keys | Action |
| --- | --- |
| `↑` `↓` `←` `→` | Scroll when the area is focused. |
| `Page Up` `Page Down` `Home` `End` | Scroll by page or to the ends. |

## Guidelines

**Do**

- Give every ScrollArea a label that describes its content.
- Keep scrolling regions few; prefer letting the page scroll.

**Don’t**

- Nest scroll areas in the same direction.
- Hide essential actions inside a scrolling region.

## Related

- https://stanceui.com/components/virtualized-list
- https://stanceui.com/components/table
