---
title: "Scroll Area"
description: "Augments native scroll functionality for custom, cross-browser styling."
canonical_url: "https://vinicunca.dev/akar/components/scroll-area"
---
# Scroll Area

> Augments native scroll functionality for custom, cross-browser styling.

## ScrollArea

```vue [index.vue]
<script setup lang="ts">
import { ScrollAreaRoot, ScrollAreaScrollbar, ScrollAreaThumb, ScrollAreaViewport } from 'akar'
import './styles.css'

const tags = Array.from({ length: 50 }).map((_, i, a) => `v1.2.0-beta.${a.length - i}`)
</script>

<template>
  <div class="akar-demo akar-demo-ScrollArea">
    <ScrollAreaRoot
        class="ScrollAreaRoot"
        style="--scrollbar-size: 10px"
      >
        <ScrollAreaViewport class="ScrollAreaViewport">
          <div :style="{ padding: '15px 20px' }">
            <div class="Text">
              Tags
            </div>
            <div
              v-for="tag in tags"
              :key="tag"
              class="Tag"
            >
              {{ tag }}
            </div>
          </div>
        </ScrollAreaViewport>
        <ScrollAreaScrollbar
          class="ScrollAreaScrollbar"
          orientation="vertical"
        >
          <ScrollAreaThumb
            class="ScrollAreaThumb"
          />
        </ScrollAreaScrollbar>
        <ScrollAreaScrollbar
          class="ScrollAreaScrollbar"
          orientation="horizontal"
        >
          <ScrollAreaThumb
            class="ScrollAreaThumb"
          />
        </ScrollAreaScrollbar>
      </ScrollAreaRoot>
  </div>
</template>
```

```css [styles.css]
@import '../_colors/black-alpha.css';
@import '../_colors/mauve.css';
@import '../_colors/grass.css';

@scope (.akar-demo-ScrollArea) {
.ScrollAreaRoot {
  width: 200px;
  height: 225px;
  border-radius: 4px;
  overflow: hidden;
  box-shadow: 0 2px 10px var(--black-a7);
  background-color: white;
  --scrollbar-size: 10px;
}

.ScrollAreaViewport {
  width: 100%;
  height: 100%;
  border-radius: inherit;
}

.ScrollAreaScrollbar {
  display: flex;
  /* ensures no selection */
  user-select: none;
  /* disable browser handling of all panning and zooming gestures on touch devices */
  touch-action: none;
  padding: 2px;
  background: var(--black-a6);
  transition: background 160ms ease-out;
}
.ScrollAreaScrollbar:hover {
  background: var(--black-a8);
}
.ScrollAreaScrollbar[data-orientation='vertical'] {
  width: var(--scrollbar-size);
}
.ScrollAreaScrollbar[data-orientation='horizontal'] {
  flex-direction: column;
  height: var(--scrollbar-size);
}

.ScrollAreaThumb {
  flex: 1;
  background: var(--mauve-10);
  border-radius: var(--scrollbar-size);
  position: relative;
}
/* increase target size for touch devices https://www.w3.org/WAI/WCAG21/Understanding/target-size.html */
.ScrollAreaThumb::before {
  content: '';
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  width: 100%;
  height: 100%;
  min-width: 44px;
  min-height: 44px;
}

.ScrollAreaCorner {
  background: var(--black-a8);
}

.Text {
  color: var(--grass-11);
  font-size: 15px;
  line-height: 18px;
  font-weight: 500;
}

.Tag {
  color: var(--mauve-12);
  font-size: 13px;
  line-height: 18px;
  margin-top: 10px;
  border-top: 1px solid var(--mauve-6);
  padding-top: 10px;
}
}
```

## Features

- Scrollbar sits on top of the scrollable content, taking up no space.
- Scrolling is native; no underlying position movements via CSS transformations.
- Shims pointer behaviors only when interacting with the controls, so keyboard controls are unaffected.
- Supports Right to Left direction.

## Installation

Install the component from your command line.

```bash [pnpm]
pnpm add akar
```

```bash [yarn]
yarn add akar
```

```bash [npm]
npm install akar
```

```bash [bun]
bun add akar
```

## Anatomy

Import all parts and piece them together.

```vue
<script setup>
import { ScrollAreaRoot, ScrollAreaScrollbar, ScrollAreaThumb, ScrollAreaViewport } from 'akar';
</script>

<template>
  <ScrollAreaRoot>
    <ScrollAreaViewport />
    <ScrollAreaScrollbar orientation="horizontal">
      <ScrollAreaThumb />
    </ScrollAreaScrollbar>
    <ScrollAreaScrollbar orientation="vertical">
      <ScrollAreaThumb />
    </ScrollAreaScrollbar>
    <ScrollAreaCorner />
  </ScrollAreaRoot>
</template>
```

## API Reference

### Root

Contains all the parts of a scroll area.

**Props**

| Prop | Default | Type | Description |
| --- | --- | --- | --- |
| `as` | `"div"` | `AsTag \| Component` | The element or component this component should render as. Can be overwritten by `asChild`. |
| `asChild` |  | `boolean` | Change the default rendered element for the one passed as a child, merging their props and behavior.<br><br>Read our [Composition](https://vinicunca.dev/akar/guides/composition) guide for more details. |
| `dir` |  | `"ltr" \| "rtl"` | The reading direction of the combobox when applicable.<br><br>If omitted, inherits globally from `ConfigProvider` or assumes LTR (left-to-right) reading mode. |
| `scrollHideDelay` | `600` | `number` | If type is set to either `scroll` or `hover`, this prop determines the length of time, in milliseconds,<br><br>before the scrollbars are hidden after the user stops interacting with scrollbars. |
| `type` | `"hover"` | `"scroll" \| "always" \| "hover" \| "auto" \| "glimpse"` | Describes the nature of scrollbar visibility, similar to how the scrollbar preferences in MacOS control visibility of native scrollbars.<br><br>`auto` - means that scrollbars are visible when content is overflowing on the corresponding orientation.<br><br>`always` - means that scrollbars are always visible regardless of whether the content is overflowing.<br><br>`scroll` - means that scrollbars are visible when the user is scrolling along its corresponding orientation.<br><br>`hover` - when the user is scrolling along its corresponding orientation and when the user is hovering over the scroll area.<br><br>`glimpse` - a hybrid approach that briefly shows scrollbars when the user enters the scroll area, then hides them until further interaction. |

**Methods**

| Method | Type | Description |
| --- | --- | --- |
| `scrollTop` | `() => void` | Scroll viewport to top |
| `scrollTopLeft` | `() => void` | Scroll viewport to top-left |

[ScrollAreaRoot.vue source](https://github.com/vinicunca/akar/blob/v2.0.20/packages/core/src/ScrollArea/ScrollAreaRoot.vue)

### Viewport

The viewport area of the scroll area.

**Props**

| Prop | Default | Type | Description |
| --- | --- | --- | --- |
| `as` | `"div"` | `AsTag \| Component` | The element or component this component should render as. Can be overwritten by `asChild`. |
| `asChild` |  | `boolean` | Change the default rendered element for the one passed as a child, merging their props and behavior.<br><br>Read our [Composition](https://vinicunca.dev/akar/guides/composition) guide for more details. |
| `nonce` |  | `string` | Will add `nonce` attribute to the style tag which can be used by Content Security Policy.<br><br>If omitted, inherits globally from `ConfigProvider`. |

[ScrollAreaViewport.vue source](https://github.com/vinicunca/akar/blob/v2.0.20/packages/core/src/ScrollArea/ScrollAreaViewport.vue)

### Scrollbar

The vertical scrollbar. Add a second `Scrollbar` with an `orientation` prop to enable horizontal scrolling.

> [!NOTE]
> 
> Defer mounting with `forceMount` / [`Presence`](https://vinicunca.dev/akar/utilities/presence). See the [animation guide](https://vinicunca.dev/akar/guides/animation).

**Props**

| Prop | Default | Type | Description |
| --- | --- | --- | --- |
| `as` | `"div"` | `AsTag \| Component` | The element or component this component should render as. Can be overwritten by `asChild`. |
| `asChild` |  | `boolean` | Change the default rendered element for the one passed as a child, merging their props and behavior.<br><br>Read our [Composition](https://vinicunca.dev/akar/guides/composition) guide for more details. |
| `forceMount` |  | `boolean` | Used to force mounting when more control is needed. Useful when<br>controlling animation with Vue animation libraries. |
| `orientation` | `"vertical"` | `"vertical" \| "horizontal"` | The orientation of the scrollbar |

[ScrollAreaScrollbar.vue source](https://github.com/vinicunca/akar/blob/v2.0.20/packages/core/src/ScrollArea/ScrollAreaScrollbar.vue)

| Data attribute | Value |
| --- | --- |
| `[data-state]` | "visible" \\| "hidden" |
| `[data-orientation]` | "vertical" \\| "horizontal" |

### Thumb

The thumb to be used in `ScrollAreaScrollbar`.

**Props**

| Prop | Default | Type | Description |
| --- | --- | --- | --- |
| `as` | `"div"` | `AsTag \| Component` | The element or component this component should render as. Can be overwritten by `asChild`. |
| `asChild` |  | `boolean` | Change the default rendered element for the one passed as a child, merging their props and behavior.<br><br>Read our [Composition](https://vinicunca.dev/akar/guides/composition) guide for more details. |

[ScrollAreaThumb.vue source](https://github.com/vinicunca/akar/blob/v2.0.20/packages/core/src/ScrollArea/ScrollAreaThumb.vue)

| Data attribute | Value |
| --- | --- |
| `[data-state]` | "visible" \\| "hidden" |

### Corner

The corner where both vertical and horizontal scrollbars meet.

**Props**

| Prop | Default | Type | Description |
| --- | --- | --- | --- |
| `as` | `"div"` | `AsTag \| Component` | The element or component this component should render as. Can be overwritten by `asChild`. |
| `asChild` |  | `boolean` | Change the default rendered element for the one passed as a child, merging their props and behavior.<br><br>Read our [Composition](https://vinicunca.dev/akar/guides/composition) guide for more details. |

[ScrollAreaCorner.vue source](https://github.com/vinicunca/akar/blob/v2.0.20/packages/core/src/ScrollArea/ScrollAreaCorner.vue)

## Examples

### Custom Scroll

Use the exposed `viewport` to modify / or set the scroll position outside default methods

```vue
<script setup lang="ts">
import { ScrollAreaRoot, ScrollAreaScrollbar, ScrollAreaThumb, ScrollAreaViewport } from 'akar'

const scrollArea = useTemplateRef('scrollArea')
function scrollToBottom() {
  const viewport = scrollArea.value?.viewport
  if (viewport) {
    const top = scrollArea.value?.$el.scrollHeight
    viewport.scrollTo({
      top,
      behavior: 'smooth'
    })
  }
}
</script>

<template>
  <ScrollAreaRoot ref="scrollArea">
    <ScrollAreaViewport />
    <ScrollAreaScrollbar orientation="horizontal">
      <ScrollAreaThumb />
    </ScrollAreaScrollbar>
    <ScrollAreaScrollbar orientation="vertical">
      <ScrollAreaThumb />
    </ScrollAreaScrollbar>
    <ScrollAreaCorner />
  </ScrollAreaRoot>
</template>
```

## Accessibility

In most cases, it's best to rely on native scrolling and work with the customization options available in CSS. When that isn't enough, `ScrollArea` provides additional customizability while maintaining the browser's native scroll behavior (as well as accessibility features, like keyboard scrolling).

### Keyboard Interactions

Scrolling via keyboard is supported by default because the component relies on native scrolling. Specific keyboard interactions may differ between platforms, so we do not specify them here or add specific event listeners to handle scrolling via key events.

---

- [GitHub](https://github.com/vinicunca/akar/blob/v2.0.20/packages/core/src/ScrollArea)
- [npm](https://www.npmjs.com/package/akar)


## Sitemap

See the full [sitemap](https://vinicunca.dev/sitemap.md) for all pages.
