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.

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.

Required styles

The scroll area requires the following styles on the viewport element to hide the native scrollbar:

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

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