{"slug":"scroll-area","title":"Scroll Area","description":"Using the scroll area machine in your project.","contentType":"component","framework":"react","content":"A scroll area provides a scrollable viewport with customizable scrollbars for\ncontent that exceeds the container's dimensions.\n\n## Resources\n\n\n[Latest version: v1.31.0](https://www.npmjs.com/package/@zag-js/scroll-area)\n[Logic Visualizer](https://zag-visualizer.vercel.app/scroll-area)\n[Source Code](https://github.com/chakra-ui/zag/tree/main/packages/machines/scroll-area)\n\n\n\n**Features**\n\n- Custom scrollbar styling and behavior\n- Smooth scrolling with easing functions\n- Touch and keyboard navigation support\n- Automatic scrollbar hiding when not needed\n- Nested scroll area support\n- Programmatic scrolling to edges or coordinates\n\n## Installation\n\nTo use the scroll area machine in your project, run the following command in\nyour command line:\n\n```bash\nnpm install @zag-js/scroll-area @zag-js/react\n# or\nyarn add @zag-js/scroll-area @zag-js/react\n```\n\n## Anatomy\n\nTo set up the scroll area correctly, you'll need to understand its anatomy and\nhow we name its parts.\n\n> Each part includes a `data-part` attribute to help identify them in the DOM.\n\n\n\n## Required style\n\nIt's important to note that the scroll area requires the following styles to be\napplied to the viewport element to hide the scrollbar:\n\n```css\n[data-scope=\"scroll-area\"][data-part=\"viewport\"] {\n  /* hide scrollbar */\n  scrollbar-width: none;\n  &::-webkit-scrollbar {\n    display: none;\n  }\n}\n```\n\n## Usage\n\nFirst, import the scroll area package into your project\n\n```jsx\nimport * as scrollArea from \"@zag-js/scroll-area\"\n```\n\nThe scroll area package exports two key functions:\n\n- `machine` — The state machine logic for the scroll area widget.\n- `connect` — The function that translates the machine's state to JSX attributes\n  and event handlers.\n\n> You'll also need to provide a unique `id` to the `useMachine` hook. This is\n> used to ensure that every part has a unique identifier.\n\nNext, import the required hooks and functions for your framework and use the\nscroll area machine in your project 🔥\n\n```jsx\nimport * as scrollArea from \"@zag-js/scroll-area\"\nimport { useMachine, normalizeProps } from \"@zag-js/react\"\nimport { useId } from \"react\"\n\nfunction ScrollArea() {\n  const service = useMachine(scrollArea.machine, {\n    id: useId(),\n  })\n\n  const api = scrollArea.connect(service, normalizeProps)\n\n  return (\n    <div {...api.getRootProps()}>\n      <div {...api.getViewportProps()}>\n        <div {...api.getContentProps()}>\n          {/* Your scrollable content here */}\n        </div>\n      </div>\n      <div {...api.getScrollbarProps()}>\n        <div {...api.getThumbProps()} />\n      </div>\n    </div>\n  )\n}\n```\n\n### Scrolling to edges\n\nYou can programmatically scroll to any edge of the scroll area using the\n`scrollToEdge` method:\n\n```jsx\n// Scroll to bottom\napi.scrollToEdge({ edge: \"bottom\" })\n\n// Scroll to top with custom easing\napi.scrollToEdge({\n  edge: \"top\",\n  duration: 500,\n  easing: (t) => t * t,\n})\n```\n\n### Scrolling to coordinates\n\nUse the `scrollTo` method to scroll to specific coordinates:\n\n```jsx\n// Scroll to specific position\napi.scrollTo({\n  top: 100,\n  left: 50,\n})\n\n// Scroll with smooth behavior\napi.scrollTo({\n  top: 200,\n  behavior: \"smooth\",\n  duration: 300,\n})\n```\n\n### Checking scroll position\n\nThe API provides several properties to check the current scroll state:\n\n```jsx\n// Check if at edges\nconsole.log(api.isAtTop) // boolean\nconsole.log(api.isAtBottom) // boolean\nconsole.log(api.isAtLeft) // boolean\nconsole.log(api.isAtRight) // boolean\n\n// Check for overflow\nconsole.log(api.hasOverflowX) // boolean\nconsole.log(api.hasOverflowY) // boolean\n\n// Get scroll progress (0-1)\nconst progress = api.getScrollProgress() // { x: number, y: number }\n```\n\n### Conditional scrollbar rendering\n\nOnly render scrollbars when there's overflow content:\n\n```jsx\n{\n  api.hasOverflowY && (\n    <div {...api.getScrollbarProps({ orientation: \"vertical\" })}>\n      <div {...api.getThumbProps({ orientation: \"vertical\" })} />\n    </div>\n  )\n}\n\n{\n  api.hasOverflowX && (\n    <div {...api.getScrollbarProps({ orientation: \"horizontal\" })}>\n      <div {...api.getThumbProps({ orientation: \"horizontal\" })} />\n    </div>\n  )\n}\n```\n\n### Scrollbar state\n\nGet the current state of a scrollbar for styling purposes:\n\n```jsx\nconst verticalState = api.getScrollbarState({ orientation: \"vertical\" })\n// Returns: { hovering: boolean, scrolling: boolean, hidden: boolean }\n```\n\n### Nested scroll areas\n\nScroll areas can be nested within each other for complex layouts:\n\n```jsx\n<div {...api.getRootProps()}>\n  <div {...api.getViewportProps()}>\n    <div {...api.getContentProps()}>\n      {/* Nested scroll area */}\n      <ScrollAreaComponent style={{ maxHeight: 200 }}>\n        {/* Inner content */}\n      </ScrollAreaComponent>\n    </div>\n  </div>\n</div>\n```\n\n## Styling guide\n\nEarlier, we mentioned that each scroll area part has a `data-part` attribute\nadded to them to select and style them in the DOM.\n\n### Scrolling state\n\nWhen the user is actively scrolling, a `data-scrolling` attribute is set on the\nscrollbar elements:\n\n```css\n[data-part=\"scrollbar\"][data-scrolling] {\n  /* styles when actively scrolling */\n}\n\n[data-part=\"thumb\"][data-scrolling] {\n  /* styles for thumb when scrolling */\n}\n```\n\n### Hover state\n\nWhen hovering over the scroll area or scrollbar, a `data-hover` attribute is\napplied:\n\n```css\n[data-part=\"root\"][data-hover] {\n  /* styles when hovering over scroll area */\n}\n\n[data-part=\"scrollbar\"][data-hover] {\n  /* styles when hovering over scrollbar */\n}\n```\n\n### Hidden state\n\nScrollbars can be automatically hidden when not needed:\n\n```css\n[data-part=\"scrollbar\"][data-hidden] {\n  /* styles for hidden scrollbar */\n  opacity: 0;\n  pointer-events: none;\n}\n```\n\n### Orientation\n\nDifferent styles can be applied based on scrollbar orientation:\n\n```css\n[data-part=\"scrollbar\"][data-orientation=\"vertical\"] {\n  /* vertical scrollbar styles */\n}\n\n[data-part=\"scrollbar\"][data-orientation=\"horizontal\"] {\n  /* horizontal scrollbar styles */\n}\n```\n\n## Methods and Properties\n\nThe scroll area's `api` exposes the following methods and properties:\n\n### Machine Context\n\nThe scroll area machine exposes the following context properties:\n\n**`ids`**\nType: `Partial<{ root: string; viewport: string; content: string; scrollbar: string; thumb: string; }>`\nDescription: The ids of the scroll area elements\n\n**`dir`**\nType: `\"ltr\" | \"rtl\"`\nDescription: The document's text/writing direction.\n\n**`id`**\nType: `string`\nDescription: The unique identifier of the machine.\n\n**`getRootNode`**\nType: `() => ShadowRoot | Node | Document`\nDescription: A root node to correctly resolve document in custom environments. E.x.: Iframes, Electron.\n\n### Machine API\n\nThe scroll area `api` exposes the following methods:\n\n**`isAtTop`**\nType: `boolean`\nDescription: Whether the scroll area is at the top\n\n**`isAtBottom`**\nType: `boolean`\nDescription: Whether the scroll area is at the bottom\n\n**`isAtLeft`**\nType: `boolean`\nDescription: Whether the scroll area is at the left\n\n**`isAtRight`**\nType: `boolean`\nDescription: Whether the scroll area is at the right\n\n**`hasOverflowX`**\nType: `boolean`\nDescription: Whether the scroll area has horizontal overflow\n\n**`hasOverflowY`**\nType: `boolean`\nDescription: Whether the scroll area has vertical overflow\n\n**`getScrollProgress`**\nType: `() => Point`\nDescription: Get the scroll progress as values between 0 and 1\n\n**`scrollToEdge`**\nType: `(details: ScrollToEdgeDetails) => void`\nDescription: Scroll to the edge of the scroll area\n\n**`scrollTo`**\nType: `(details: ScrollToDetails) => void`\nDescription: Scroll to specific coordinates\n\n**`getScrollbarState`**\nType: `(props: ScrollbarProps) => ScrollbarState`\nDescription: Returns the state of the scrollbar\n\n### Data Attributes\n\n**`Root`**\n\n**`data-scope`**: scroll-area\n**`data-part`**: root\n**`data-overflow-x`**: Present when the content overflows the x-axis\n**`data-overflow-y`**: Present when the content overflows the y-axis\n\n**`Viewport`**\n\n**`data-scope`**: scroll-area\n**`data-part`**: viewport\n**`data-at-top`**: Present when scrolled to the top edge\n**`data-at-bottom`**: Present when scrolled to the bottom edge\n**`data-at-left`**: Present when scrolled to the left edge\n**`data-at-right`**: Present when scrolled to the right edge\n**`data-overflow-x`**: Present when the content overflows the x-axis\n**`data-overflow-y`**: Present when the content overflows the y-axis\n\n**`Content`**\n\n**`data-scope`**: scroll-area\n**`data-part`**: content\n**`data-overflow-x`**: Present when the content overflows the x-axis\n**`data-overflow-y`**: Present when the content overflows the y-axis\n\n**`Scrollbar`**\n\n**`data-scope`**: scroll-area\n**`data-part`**: scrollbar\n**`data-orientation`**: The orientation of the scrollbar\n**`data-scrolling`**: Present when scrolling\n**`data-hover`**: Present when hovered\n**`data-dragging`**: Present when in the dragging state\n**`data-overflow-x`**: Present when the content overflows the x-axis\n**`data-overflow-y`**: Present when the content overflows the y-axis\n\n**`Thumb`**\n\n**`data-scope`**: scroll-area\n**`data-part`**: thumb\n**`data-orientation`**: The orientation of the thumb\n**`data-hover`**: Present when hovered\n**`data-dragging`**: Present when in the dragging state\n\n**`Corner`**\n\n**`data-scope`**: scroll-area\n**`data-part`**: corner\n**`data-hover`**: Present when hovered\n**`data-state`**: \"hidden\" | \"visible\"\n**`data-overflow-x`**: Present when the content overflows the x-axis\n**`data-overflow-y`**: Present when the content overflows the y-axis\n\n### CSS Variables\n\n<CssVarTable name=\"scroll-area\" />","package":"@zag-js/scroll-area","editUrl":"https://github.com/chakra-ui/zag/edit/main/website/data/components/scroll-area.mdx"}