{"slug":"range-slider","title":"Range Slider","description":"Using the range slider machine in your project.","contentType":"component","framework":"react","content":"A range slider is a multi-thumb slider used to select a range between two\nnumbers.\n\n## Resources\n\n\n[Latest version: v1.35.3](https://www.npmjs.com/package/@zag-js/slider)\n[Logic Visualizer](https://zag-visualizer.vercel.app/slider)\n[Source Code](https://github.com/chakra-ui/zag/tree/main/packages/machines/slider)\n\n\n\n**Features**\n\n- Fully managed keyboard navigation\n- Supports touch or click on track to update value\n- Supports Right-to-Left directionality\n- Supports horizontal and vertical orientations\n- Prevents text selection while dragging\n\n## Installation\n\nInstall the range slider package:\n\n```bash\nnpm install @zag-js/slider @zag-js/react\n# or\nyarn add @zag-js/slider @zag-js/react\n```\n\n## Anatomy\n\nCheck the slider anatomy and part names.\n\n> Each part includes a `data-part` attribute to help identify them in the DOM.\n\n\n\n## Usage\n\nImport the range slider package:\n\n```jsx\nimport * as rangeSlider from \"@zag-js/slider\"\n```\n\nThe range slider package exports two key functions:\n\n- `machine` - State machine logic.\n- `connect` - Maps machine state to JSX props and event handlers.\n\n> Pass a unique `id` to `useMachine` so generated element ids stay predictable.\n\nThen use the framework integration helpers:\n\n```jsx\nimport * as slider from \"@zag-js/slider\"\nimport { useMachine, normalizeProps } from \"@zag-js/react\"\n\nexport function RangeSlider() {\n  const service = useMachine(slider.machine, {\n    id: \"1\",\n    name: \"quantity\",\n    defaultValue: [10, 60],\n  })\n\n  const api = slider.connect(service, normalizeProps)\n\n  return (\n    <div {...api.getRootProps()}>\n      <div {...api.getControlProps()}>\n        <div {...api.getTrackProps()}>\n          <div {...api.getRangeProps()} />\n        </div>\n        {api.value.map((_, index) => (\n          <div key={index} {...api.getThumbProps({ index })}>\n            <input {...api.getHiddenInputProps({ index })} />\n          </div>\n        ))}\n      </div>\n    </div>\n  )\n}\n```\n\n## Changing the orientation\n\nBy default, the slider is assumed to be horizontal. To change the orientation to\nvertical, set the `orientation` property in the machine's context to `vertical`.\n\nIn this mode, the slider will use the arrow up and down keys to\nincrement/decrement its value.\n\n> Don't forget to change the styles of the vertical slider by specifying its\n> height\n\n```jsx {2}\nconst service = useMachine(rangeSlider.machine, {\n  orientation: \"vertical\",\n})\n```\n\n## Setting the initial value\n\n```jsx {2}\nconst service = useMachine(rangeSlider.machine, {\n  defaultValue: [30, 60],\n})\n```\n\n## Controlled range value\n\nUse `value` and `onValueChange` to control both thumb values externally.\n\n```jsx\nconst service = useMachine(rangeSlider.machine, {\n  value,\n  onValueChange(details) {\n    setValue(details.value)\n  },\n})\n```\n\n## Specifying the minimum and maximum\n\nBy default, the minimum is `0` and the maximum is `100`. If that's not what you\nwant, you can easily specify different bounds by changing the values of the min\nand/or max attributes.\n\nFor example, to ask the user for a value between `-10` and `10`, you can use:\n\n```jsx {2-3}\nconst service = useMachine(rangeSlider.machine, {\n  min: -10,\n  max: 10,\n})\n```\n\n## Setting the value's granularity\n\nBy default, the granularity, is `1`, meaning that the value is always an\ninteger. You can change the step attribute to control the granularity.\n\nFor example, If you need a value between `5` and `10`, accurate to two decimal\nplaces, you should set the value of step to `0.01`:\n\n```jsx {4}\nconst service = useMachine(rangeSlider.machine, {\n  min: 5,\n  max: 10,\n  step: 0.01,\n})\n```\n\n## Listening for changes\n\nWhen the slider value changes, the `onValueChange` and `onValueChangeEnd`\ncallbacks are invoked. You can use this to setup custom behaviors in your app.\n\n```jsx {2-7}\nconst service = useMachine(rangeSlider.machine, {\n  onValueChange(details) {\n    // details => { value: number[] }\n    console.log(\"value changing to:\", details.value)\n  },\n  onValueChangeEnd(details) {\n    // details => { value: number[] }\n    console.log(\"value has changed to:\", details.value)\n  },\n})\n```\n\n## Listening for thumb focus changes\n\nUse `onFocusChange` to track which thumb is currently focused.\n\n```jsx\nconst service = useMachine(rangeSlider.machine, {\n  onFocusChange(details) {\n    // details => { focusedIndex: number, value: number[] }\n    console.log(\"focused thumb:\", details.focusedIndex)\n  },\n})\n```\n\n## Preventing thumb overlap\n\nBy default, the range slider thumbs are allowed to overlap when their values are\nequal. To prevent this, use the `minStepsBetweenThumbs` to avoid thumbs with\nequal values.\n\n```jsx {2}\nconst service = useMachine(rangeSlider.machine, {\n  minStepsBetweenThumbs: 1,\n})\n```\n\n## Thumb collision behavior\n\nUse `thumbCollisionBehavior` to control how thumbs behave on collision.\n\n```jsx\nconst service = useMachine(rangeSlider.machine, {\n  defaultValue: [20, 80],\n  thumbCollisionBehavior: \"push\", // \"none\" | \"push\" | \"swap\"\n})\n```\n\n## Usage within forms\n\nTo use range slider in forms, set `name` and render\n`api.getHiddenInputProps({ index })` for each thumb.\n\n```jsx {2}\nconst service = useMachine(rangeSlider.machine, {\n  name: \"quantity\",\n})\n```\n\n## RTL Support\n\nThe slider has built-in support for RTL alignment and interaction. In the RTL\nmode, operations are performed from right to left, meaning, the left arrow key\nwill increment and the right arrow key will decrement.\n\nTo enable RTL support, pass the `dir: rtl` context property\n\n```jsx {2}\nconst service = useMachine(rangeSlider.machine, {\n  dir: \"rtl\",\n})\n```\n\n> While we take care of the interactions in RTL mode, you'll have to ensure you\n> apply the correct CSS styles to flip the layout.\n\n## Styling guide\n\nEach slider part includes a `data-part` attribute you can target in CSS.\n\n### Focused State\n\nWhen the slider thumb is focused, the `data-focus` attribute is added to the\nroot, control, thumb and label parts.\n\n```css\n[data-part=\"root\"][data-focus] {\n  /* styles for root focus state */\n}\n\n[data-part=\"thumb\"]:focus {\n  /* styles for thumb focus state */\n}\n\n[data-part=\"control\"][data-focus] {\n  /* styles for control focus state */\n}\n\n[data-part=\"track\"][data-focus] {\n  /* styles for track focus state */\n}\n\n[data-part=\"range\"][data-focus] {\n  /* styles for range focus state */\n}\n```\n\n### Disabled State\n\nWhen the slider is disabled, the `data-disabled` attribute is added to the root,\nlabel, control and thumb.\n\n```css\n[data-part=\"root\"][data-disabled] {\n  /* styles for root disabled state */\n}\n\n[data-part=\"label\"][data-disabled] {\n  /* styles for label disabled state */\n}\n\n[data-part=\"control\"][data-disabled] {\n  /* styles for control disabled state */\n}\n\n[data-part=\"value-text\"][data-disabled] {\n  /* styles for output disabled state */\n}\n\n[data-part=\"thumb\"][data-disabled] {\n  /* styles for thumb disabled state */\n}\n\n[data-part=\"range\"][data-disabled] {\n  /* styles for range disabled state */\n}\n```\n\n### Orientation\n\n```css\n[data-part=\"root\"][data-orientation=\"(horizontal|vertical)\"] {\n  /* styles for horizontal or vertical  */\n}\n\n[data-part=\"thumb\"][data-orientation=\"(horizontal|vertical)\"] {\n  /* styles for horizontal or vertical  */\n}\n\n[data-part=\"track\"][data-orientation=\"(horizontal|vertical)\"] {\n  /* styles for horizontal or vertical  */\n}\n```\n\n## Methods and Properties\n\n### Machine Context\n\nThe slider machine exposes the following context properties:\n\n<ContextTable name=\"slider\" />\n\n### Machine API\n\nThe slider `api` exposes the following methods:\n\n<ApiTable name=\"slider\" />\n\n### Data Attributes\n\n<DataAttrTable name=\"slider\" />\n\n## Accessibility\n\nAdheres to the\n[Slider WAI-ARIA design pattern](https://www.w3.org/WAI/ARIA/apg/patterns/slidertwothumb).\n\n### Keyboard Interactions\n\n**`ArrowRight`**\nDescription: <span>Increments the focused thumb based on defined step</span>\n\n**`ArrowLeft`**\nDescription: <span>Decrements the focused thumb based on defined step</span>\n\n**`ArrowUp`**\nDescription: <span>Increases the focused thumb by the step amount.</span>\n\n**`ArrowDown`**\nDescription: <span>Decreases the focused thumb by the step amount.</span>\n\n**`PageUp`**\nDescription: <span>Increases the focused thumb value by a larger step</span>\n\n**`PageDown`**\nDescription: <span>Decreases the focused thumb value by a larger step</span>\n\n**`Shift + ArrowUp`**\nDescription: <span>Increases the focused thumb value by a larger step</span>\n\n**`Shift + ArrowDown`**\nDescription: <span>Decreases the focused thumb value by a larger step</span>\n\n**`Home`**\nDescription: Sets the focused thumb value to its minimum.\n\n**`End`**\nDescription: Sets the focused thumb value to its maximum.","package":"@zag-js/slider","editUrl":"https://github.com/chakra-ui/zag/edit/main/website/data/components/range-slider.mdx"}