Scroll Area

Consistent scroll area across platforms.

Scroll Area

Lorem ipsum dolor sit, amet consectetur adipisicing elit. Dignissimos impedit rem, repellat deserunt ducimus quasi nisi voluptatem cumque aliquid esse ea deleniti eveniet incidunt! Deserunt minus laborum accusamus iusto dolorum. Lorem ipsum dolor sit, amet consectetur adipisicing elit. Blanditiis officiis error minima eos fugit voluptate excepturi eveniet dolore et, ratione impedit consequuntur dolorem hic quae corrupti autem? Dolorem, sit voluptatum.

	<script lang="ts">
  import { ScrollArea } from "bits-ui";
</script>
 
<ScrollArea.Root
  class="relative overflow-hidden rounded-[10px] border border-dark-10 bg-background-alt px-4 py-4 shadow-card"
>
  <ScrollArea.Viewport class="h-full max-h-[200px] w-full max-w-[200px]">
    <h4
      class="mb-4 mt-2 text-xl font-semibold leading-none tracking-[-0.01em] text-foreground"
    >
      Scroll Area
    </h4>
    <p class="text-wrap text-sm leading-5 text-foreground-alt">
      Lorem ipsum dolor sit, amet consectetur adipisicing elit. Dignissimos
      impedit rem, repellat deserunt ducimus quasi nisi voluptatem cumque
      aliquid esse ea deleniti eveniet incidunt! Deserunt minus laborum
      accusamus iusto dolorum. Lorem ipsum dolor sit, amet consectetur
      adipisicing elit. Blanditiis officiis error minima eos fugit voluptate
      excepturi eveniet dolore et, ratione impedit consequuntur dolorem hic quae
      corrupti autem? Dolorem, sit voluptatum.
    </p>
  </ScrollArea.Viewport>
  <ScrollArea.Scrollbar
    orientation="vertical"
    class="flex w-2.5 touch-none select-none rounded-full border-l border-l-transparent bg-muted p-px transition-all duration-200 hover:w-3 hover:bg-dark-10 data-[state=visible]:animate-in data-[state=hidden]:animate-out data-[state=hidden]:fade-out-0 data-[state=visible]:fade-in-0"
  >
    <ScrollArea.Thumb class="flex-1 rounded-full bg-muted-foreground" />
  </ScrollArea.Scrollbar>
  <ScrollArea.Scrollbar
    orientation="horizontal"
    class="flex h-2.5 touch-none select-none rounded-full border-t border-t-transparent bg-muted p-px transition-all duration-200 hover:h-3 hover:bg-dark-10 data-[state=visible]:animate-in data-[state=hidden]:animate-out data-[state=hidden]:fade-out-0 data-[state=visible]:fade-in-0"
  >
    <ScrollArea.Thumb class="rounded-full bg-muted-foreground" />
  </ScrollArea.Scrollbar>
  <ScrollArea.Corner />
</ScrollArea.Root>

Structure

	<script lang="ts">
	import { ScrollArea } from "bits-ui";
</script>
 
<ScrollArea.Root>
	<ScrollArea.Viewport>
		<!-- Scrollable content here -->
	</ScrollArea.Viewport>
	<ScrollArea.Scrollbar orientation="vertical">
		<ScrollArea.Thumb />
	</ScrollArea.Scrollbar>
	<ScrollArea.Scrollbar orientation="horizontal">
		<ScrollArea.Thumb />
	</ScrollArea.Scrollbar>
	<ScrollArea.Corner />
</ScrollArea.Root>

Reusable Components

If you're planning to use the Scroll Area throughout your application, it's recommended to create a reusable component to reduce the amount of code you need to write each time.

This example shows you how to create a Scroll Area component that accepts a few custom props that make it more capable.

MyScrollArea.svelte
	<script lang="ts">
	import { ScrollArea, type WithoutChild } from "bits-ui";
 
	type Props = WithoutChild<ScrollArea.RootProps> & {
		orientation: "vertical" | "horizontal" | "both";
		viewportClasses?: string;
	};
 
	let {
		ref = $bindable(null),
		orientation = "vertical",
		viewportClasses,
		children,
		...restProps
	}: Props = $props();
</script>
 
{#snippet Scrollbar({ orientation }: { orientation: "vertical" | "horizontal" })}
	<ScrollArea.Scrollbar {orientation}>
		<ScrollArea.Thumb />
	</ScrollArea.Scrollbar>
{/snippet}
 
<ScrollArea.Root bind:ref {...restProps}>
	<ScrollArea.Viewport class={viewportClasses}>
		{@render children?.()}
	</ScrollArea.Viewport>
	{#if orientation === "vertical" || orientation === "both"}
		{@render Scrollbar({ orientation: "vertical" })}
	{/if}
	{#if orientation === "horizontal" || orientation === "both"}
		{@render Scrollbar({ orientation: "horizontal" })}
	{/if}
	<ScrollArea.Corner />
</ScrollArea.Root>

We'll use this custom component in the following examples to demonstrate how to customize the behavior of the Scroll Area.

Scroll Area Types

Hover

The hover type is the default type of the scroll area, demonstrated in the featured example above. It only shows scrollbars when the user hovers over the scroll area and the content is larger than the viewport.

	<MyScrollArea type="hover">
	<!-- ... -->
</MyScrollArea>

Scroll Area

Lorem ipsum dolor sit, amet consectetur adipisicing elit. Dignissimos impedit rem, repellat deserunt ducimus quasi nisi voluptatem cumque aliquid esse ea deleniti eveniet incidunt! Deserunt minus laborum accusamus iusto dolorum. Lorem ipsum dolor sit, amet consectetur adipisicing elit. Blanditiis officiis error minima eos fugit voluptate excepturi eveniet dolore et, ratione impedit consequuntur dolorem hic quae corrupti autem? Dolorem, sit voluptatum.

Scroll

The scroll type displays the scrollbars when the user scrolls the content. This is similar to the behavior of MacOS.

	<MyScrollArea type="scroll">
	<!-- ... -->
</MyScrollArea>

Scroll Area

Lorem ipsum dolor sit, amet consectetur adipisicing elit. Dignissimos impedit rem, repellat deserunt ducimus quasi nisi voluptatem cumque aliquid esse ea deleniti eveniet incidunt! Deserunt minus laborum accusamus iusto dolorum. Lorem ipsum dolor sit, amet consectetur adipisicing elit. Blanditiis officiis error minima eos fugit voluptate excepturi eveniet dolore et, ratione impedit consequuntur dolorem hic quae corrupti autem? Dolorem, sit voluptatum.

Auto

The auto type behaves similarly to your typical browser scrollbars. When the content is larger than the viewport, the scrollbars will appear and remain visible at all times.

	<MyScrollArea type="auto">
	<!-- ... -->
</MyScrollArea>

Scroll Area

Lorem ipsum dolor sit, amet consectetur adipisicing elit. Dignissimos impedit rem, repellat deserunt ducimus quasi nisi voluptatem cumque aliquid esse ea deleniti eveniet incidunt! Deserunt minus laborum accusamus iusto dolorum. Lorem ipsum dolor sit, amet consectetur adipisicing elit. Blanditiis officiis error minima eos fugit voluptate excepturi eveniet dolore et, ratione impedit consequuntur dolorem hic quae corrupti autem? Dolorem, sit voluptatum.

Always

The always type behaves as if you set overflow: scroll on the scroll area. Scrollbars will always be visible, even when the content is smaller than the viewport. We've also set the orientation prop on the MyScrollArea to 'both' to ensure both scrollbars are rendered.

	<MyScrollArea type="always" orientation="both">
	<!-- ... -->
</MyScrollArea>

Scroll Area

Lorem ipsum dolor sit, amet consectetur adipisicing elit. Dignissimos impedit rem, repellat deserunt ducimus quasi nisi voluptatem cumque aliquid esse ea deleniti eveniet incidunt! Deserunt minus laborum accusamus iusto dolorum. Lorem ipsum dolor sit, amet consectetur adipisicing elit. Blanditiis officiis error minima eos fugit voluptate excepturi eveniet dolore et, ratione impedit consequuntur dolorem hic quae corrupti autem? Dolorem, sit voluptatum.

Customizing the Hide Delay

You can customize the hide delay of the scrollbars using the scrollHideDelay prop.

	<MyScrollArea scrollHideDelay={10}>
	<!-- ... -->
</MyScrollArea>

Scroll Area

Lorem ipsum dolor sit, amet consectetur adipisicing elit. Dignissimos impedit rem, repellat deserunt ducimus quasi nisi voluptatem cumque aliquid esse ea deleniti eveniet incidunt! Deserunt minus laborum accusamus iusto dolorum. Lorem ipsum dolor sit, amet consectetur adipisicing elit. Blanditiis officiis error minima eos fugit voluptate excepturi eveniet dolore et, ratione impedit consequuntur dolorem hic quae corrupti autem? Dolorem, sit voluptatum.

API Reference

ScrollArea.Root

The container of all scroll area components. Overflow is hidden on this element to prevent double scrollbars.

Property Type Description
type
enum

The type of scroll area.

Default: 'hover'
scrollHideDelay
number

The delay in milliseconds before the scroll area hides itself when using 'hover' or 'scroll' type.

Default: 600
dir
enum

The reading direction of the app.

Default: ltr
ref bindable prop
HTMLDivElement

The underlying DOM element being rendered. You can bind to this to get a reference to the element.

Default: undefined
children
Snippet

The children content to render.

Default: undefined
child
Snippet

Use render delegation to render your own element. See delegation docs for more information.

Default: undefined
Data Attribute Value Description
data-scroll-area-root
''

Present on the root element.

ScrollArea.Viewport

The component which wraps the content and is responsible for computing the scroll area size.

Property Type Description
ref bindable prop
HTMLDivElement

The underlying DOM element being rendered. You can bind to this to get a reference to the element.

Default: undefined
children
Snippet

The children content to render.

Default: undefined
Data Attribute Value Description
data-scroll-area-viewport
''

Present on the viewport element.

ScrollArea.Scrollbar

A scrollbar of the scroll area.

Property Type Description
orientation required prop
enum

The orientation of the scrollbar.

Default: undefined
forceMount
boolean

Whether or not to forcefully mount the content. This is useful if you want to use Svelte transitions or another animation library for the content.

Default: false
ref bindable prop
HTMLDivElement

The underlying DOM element being rendered. You can bind to this to get a reference to the element.

Default: undefined
children
Snippet

The children content to render.

Default: undefined
child
Snippet

Use render delegation to render your own element. See delegation docs for more information.

Default: undefined
Data Attribute Value Description
data-state
enum

The visibility state of the scrollbar

data-scroll-area-scrollbar-x
''

Present on 'horizontal' scrollbar element.

data-scroll-area-scrollbar-y
''

Present on the 'vertical' scrollbar element.

ScrollArea.Thumb

A thumb of a scrollbar in the scroll area.

Property Type Description
forceMount
boolean

Whether or not to forcefully mount the content. This is useful if you want to use Svelte transitions or another animation library for the content.

Default: false
ref bindable prop
HTMLDivElement

The underlying DOM element being rendered. You can bind to this to get a reference to the element.

Default: undefined
children
Snippet

The children content to render.

Default: undefined
child
Snippet

Use render delegation to render your own element. See delegation docs for more information.

Default: undefined
Data Attribute Value Description
data-state
enum

The visibility state of the scrollbar

data-scroll-area-thumb-x
''

Present on 'horizontal' thumb element.

data-scroll-area-thumb-y
''

Present on the 'vertical' thumb element.

ScrollArea.Corner

The corner element between the X and Y scrollbars.

Property Type Description
ref bindable prop
HTMLDivElement

The underlying DOM element being rendered. You can bind to this to get a reference to the element.

Default: undefined
children
Snippet

The children content to render.

Default: undefined
child
Snippet

Use render delegation to render your own element. See delegation docs for more information.

Default: undefined
Data Attribute Value Description
data-scroll-area-corner
''

Present on the corner element.