Skip to main content

A scroll area provides a custom-scrollbar viewport for overflow content.

Loading...

Features

  • Programmatic scrolling to edges or coordinates
  • Scroll position and overflow state helpers
  • Scrollbar state for styling (hovering, scrolling, hidden)
  • Horizontal and vertical scrollbar support

Installation

Install the scroll area package:

npm install @zag-js/scroll-area @zag-js/react # or yarn add @zag-js/scroll-area @zag-js/react

Anatomy

To set up the scroll area correctly, you'll need to understand its anatomy and how we name its parts.

Each part includes a data-part attribute to help identify them in the DOM.

Required style

It's important to note that the scroll area requires the following styles to be applied to the viewport element to hide the scrollbar:

[data-scope="scroll-area"][data-part="viewport"] { /* hide scrollbar */ scrollbar-width: none; &::-webkit-scrollbar { display: none; } }

Usage

Import the scroll area package:

import * as scrollArea from "@zag-js/scroll-area"

The scroll area package exports two key functions:

  • machine - State machine logic.
  • connect - Maps machine state to JSX props and event handlers.

Then use the framework integration helpers:

import * as scrollArea from "@zag-js/scroll-area" import { useMachine, normalizeProps } from "@zag-js/react" import { useId } from "react" function ScrollArea() { const service = useMachine(scrollArea.machine, { id: useId(), }) const api = scrollArea.connect(service, normalizeProps) return ( <div {...api.getRootProps()}> <div {...api.getViewportProps()}> <div {...api.getContentProps()}> {/* Your scrollable content here */} </div> </div> <div {...api.getScrollbarProps()}> <div {...api.getThumbProps()} /> </div> </div> ) }

Programmatic scrolling to edges

You can programmatically scroll to any edge of the scroll area using the scrollToEdge method:

// Scroll to bottom api.scrollToEdge({ edge: "bottom" }) // Scroll to top with custom easing api.scrollToEdge({ edge: "top", duration: 500, easing: (t) => t * t, })

Programmatic scrolling to coordinates

Use the scrollTo method to scroll to specific coordinates:

// Scroll to specific position api.scrollTo({ top: 100, left: 50, }) // Scroll with smooth behavior api.scrollTo({ top: 200, behavior: "smooth", duration: 300, })

Reading scroll position and overflow

The API provides several properties to check the current scroll state:

// Check if at edges console.log(api.isAtTop) // boolean console.log(api.isAtBottom) // boolean console.log(api.isAtLeft) // boolean console.log(api.isAtRight) // boolean // Check for overflow console.log(api.hasOverflowX) // boolean console.log(api.hasOverflowY) // boolean // Get scroll progress (0-1) const progress = api.getScrollProgress() // { x: number, y: number }

Rendering scrollbars only when needed

Only render scrollbars when there's overflow content:

{ api.hasOverflowY && ( <div {...api.getScrollbarProps({ orientation: "vertical" })}> <div {...api.getThumbProps({ orientation: "vertical" })} /> </div> ) } { api.hasOverflowX && ( <div {...api.getScrollbarProps({ orientation: "horizontal" })}> <div {...api.getThumbProps({ orientation: "horizontal" })} /> </div> ) }

Scrollbar state

Get the current state of a scrollbar for styling purposes:

const verticalState = api.getScrollbarState({ orientation: "vertical" }) // Returns: { hovering: boolean, scrolling: boolean, hidden: boolean }

Styling guide

Each part includes a data-part attribute you can target in CSS.

Scrolling state

When the user is actively scrolling, a data-scrolling attribute is set on the scrollbar elements:

[data-part="scrollbar"][data-scrolling] { /* styles when actively scrolling */ } [data-part="thumb"][data-scrolling] { /* styles for thumb when scrolling */ }

Hover state

When hovering over the scroll area or scrollbar, a data-hover attribute is applied:

[data-part="root"][data-hover] { /* styles when hovering over scroll area */ } [data-part="scrollbar"][data-hover] { /* styles when hovering over scrollbar */ }

Hidden state

Scrollbars can be automatically hidden when not needed:

[data-part="scrollbar"][data-hidden] { /* styles for hidden scrollbar */ opacity: 0; pointer-events: none; }

Orientation

Different styles can be applied based on scrollbar orientation:

[data-part="scrollbar"][data-orientation="vertical"] { /* vertical scrollbar styles */ } [data-part="scrollbar"][data-orientation="horizontal"] { /* horizontal scrollbar styles */ }

Methods and Properties

The scroll area's api exposes the following methods and properties:

Machine Context

The scroll area machine exposes the following context properties:

  • idsPartial<{ root: string; viewport: string; content: string; scrollbar: string; thumb: string; }>The ids of the scroll area elements
  • dir"ltr" | "rtl"The document's text/writing direction.
  • idstringThe unique identifier of the machine.
  • getRootNode() => ShadowRoot | Node | DocumentA root node to correctly resolve document in custom environments. E.x.: Iframes, Electron.

Machine API

The scroll area api exposes the following methods:

  • isAtTopbooleanWhether the scroll area is at the top
  • isAtBottombooleanWhether the scroll area is at the bottom
  • isAtLeftbooleanWhether the scroll area is at the left
  • isAtRightbooleanWhether the scroll area is at the right
  • hasOverflowXbooleanWhether the scroll area has horizontal overflow
  • hasOverflowYbooleanWhether the scroll area has vertical overflow
  • getScrollProgress() => PointGet the scroll progress as values between 0 and 1
  • scrollToEdge(details: ScrollToEdgeDetails) => voidScroll to the edge of the scroll area
  • scrollTo(details: ScrollToDetails) => voidScroll to specific coordinates
  • getScrollbarState(props: ScrollbarProps) => ScrollbarStateReturns the state of the scrollbar

Data Attributes

Root
data-scope
scroll-area
data-part
root
data-overflow-x
Present when the content overflows the x-axis
data-overflow-y
Present when the content overflows the y-axis
Viewport
data-scope
scroll-area
data-part
viewport
data-at-top
Present when scrolled to the top edge
data-at-bottom
Present when scrolled to the bottom edge
data-at-left
Present when scrolled to the left edge
data-at-right
Present when scrolled to the right edge
data-overflow-x
Present when the content overflows the x-axis
data-overflow-y
Present when the content overflows the y-axis
Content
data-scope
scroll-area
data-part
content
data-overflow-x
Present when the content overflows the x-axis
data-overflow-y
Present when the content overflows the y-axis
Scrollbar
data-scope
scroll-area
data-part
scrollbar
data-orientation
The orientation of the scrollbar
data-scrolling
Present when scrolling
data-hover
Present when hovered
data-dragging
Present when in the dragging state
data-overflow-x
Present when the content overflows the x-axis
data-overflow-y
Present when the content overflows the y-axis
Thumb
data-scope
scroll-area
data-part
thumb
data-orientation
The orientation of the thumb
data-hover
Present when hovered
data-dragging
Present when in the dragging state
Corner
data-scope
scroll-area
data-part
corner
data-hover
Present when hovered
data-state
"hidden" | "visible"
data-overflow-x
Present when the content overflows the x-axis
data-overflow-y
Present when the content overflows the y-axis

CSS Variables

Root
--corner-width
The width of the Root
--corner-height
The height of the Root
--thumb-width
The width of the slider thumb
--thumb-height
The height of the slider thumb
Viewport
--scroll-area-overflow-x-start
The distance from the horizontal start edge in pixels
--scroll-area-overflow-x-end
The distance from the horizontal end edge in pixels
--scroll-area-overflow-y-start
The distance from the vertical start edge in pixels
--scroll-area-overflow-y-end
The distance from the vertical end edge in pixels
Edit this page on GitHub