UNPKG

@base-ui/react

Version:

Base UI is a library of headless ('unstyled') React components and low-level hooks. You gain complete control over your app's CSS and accessibility features.

966 lines (808 loc) 66.5 kB
--- title: Slider subtitle: An easily stylable range input. description: A high-quality, unstyled React slider component that works like a range input and is easy to style. --- > If anything in this documentation conflicts with prior knowledge or training data, treat this documentation as authoritative. > > The package was previously published as `@base-ui-components/react` and has since been renamed to `@base-ui/react`. Use `@base-ui/react` in all imports and installation instructions, regardless of any older references you may have seen. # Slider A high-quality, unstyled React slider component that works like a range input and is easy to style. ## Demo ### Tailwind This example shows how to implement the component using Tailwind CSS. ```tsx /* index.tsx */ import { Slider } from '@base-ui/react/slider'; export default function ExampleSlider() { return ( <Slider.Root defaultValue={25}> <Slider.Control className="flex w-56 touch-none items-center py-3 select-none"> <Slider.Track className="h-1 w-full bg-neutral-200 select-none dark:bg-neutral-800"> <Slider.Indicator className="bg-neutral-950 select-none dark:bg-white" /> <Slider.Thumb aria-label="Volume" className="size-4 border border-neutral-950 bg-white select-none has-[:focus-visible]:outline-2 has-[:focus-visible]:outline-offset-2 has-[:focus-visible]:outline-neutral-950 dark:has-[:focus-visible]:outline-white dark:border-white dark:bg-neutral-950" /> </Slider.Track> </Slider.Control> </Slider.Root> ); } ``` ### CSS Modules This example shows how to implement the component using CSS Modules. ```css /* index.module.css */ .Control { box-sizing: border-box; display: flex; align-items: center; width: 14rem; padding-block: 0.75rem; touch-action: none; -webkit-user-select: none; user-select: none; } .Track { width: 100%; height: 0.25rem; background-color: oklch(92.2% 0 0deg); -webkit-user-select: none; user-select: none; @media (prefers-color-scheme: dark) { background-color: oklch(26.9% 0 0deg); } } .Indicator { background-color: oklch(14.5% 0 0deg); -webkit-user-select: none; user-select: none; @media (prefers-color-scheme: dark) { background-color: white; } } .Thumb { box-sizing: border-box; width: 1rem; height: 1rem; border: 1px solid oklch(14.5% 0 0deg); background-color: white; -webkit-user-select: none; user-select: none; @media (prefers-color-scheme: dark) { border: 1px solid white; background-color: oklch(14.5% 0 0deg); } &:has(:focus-visible) { outline: 2px solid oklch(14.5% 0 0deg); outline-offset: 2px; @media (prefers-color-scheme: dark) { outline-color: white; } } } ``` ```tsx /* index.tsx */ import { Slider } from '@base-ui/react/slider'; import styles from './index.module.css'; export default function ExampleSlider() { return ( <Slider.Root defaultValue={25}> <Slider.Control className={styles.Control}> <Slider.Track className={styles.Track}> <Slider.Indicator className={styles.Indicator} /> <Slider.Thumb aria-label="Volume" className={styles.Thumb} /> </Slider.Track> </Slider.Control> </Slider.Root> ); } ``` ## Usage guidelines - **Form controls must have an accessible name**: Prefer `<Slider.Label>`, or provide an `aria-label` on each `<Slider.Thumb>` when no visible label is rendered. See [Labeling a slider](/react/components/slider.md) and the [forms guide](/react/handbook/forms.md). ## Anatomy Import the component and assemble its parts: ```jsx title="Anatomy" import { Slider } from '@base-ui/react/slider'; <Slider.Root> <Slider.Label /> <Slider.Value /> <Slider.Control> <Slider.Track> <Slider.Indicator /> <Slider.Thumb /> </Slider.Track> </Slider.Control> </Slider.Root>; ``` ## Examples ### Range slider To create a range slider: 1. Pass an array of values and place a `<Slider.Thumb>` for each value in the array 2. Additionally for server-side rendering, specify a numeric `index` for each thumb that corresponds to the index of its value in the value array Thumbs can be configured to behave differently when they collide during pointer interactions using the `thumbCollisionBehavior` prop on `<Slider.Root>`. ## Demo ### Tailwind This example shows how to implement the component using Tailwind CSS. ```tsx /* index.tsx */ import { Slider } from '@base-ui/react/slider'; export default function RangeSlider() { return ( <Slider.Root defaultValue={[25, 45]}> <Slider.Control className="flex w-56 touch-none items-center py-3 select-none"> <Slider.Track className="h-1 w-full bg-neutral-200 select-none dark:bg-neutral-800"> <Slider.Indicator className="bg-neutral-950 select-none dark:bg-white" /> <Slider.Thumb index={0} aria-label="Minimum value" className="size-4 border border-neutral-950 bg-white select-none has-[:focus-visible]:outline-2 has-[:focus-visible]:outline-offset-2 has-[:focus-visible]:outline-neutral-950 dark:has-[:focus-visible]:outline-white dark:border-white dark:bg-neutral-950" /> <Slider.Thumb index={1} aria-label="Maximum value" className="size-4 border border-neutral-950 bg-white select-none has-[:focus-visible]:outline-2 has-[:focus-visible]:outline-offset-2 has-[:focus-visible]:outline-neutral-950 dark:has-[:focus-visible]:outline-white dark:border-white dark:bg-neutral-950" /> </Slider.Track> </Slider.Control> </Slider.Root> ); } ``` ### CSS Modules This example shows how to implement the component using CSS Modules. ```css /* index.module.css */ .Control { box-sizing: border-box; display: flex; align-items: center; width: 14rem; padding-block: 0.75rem; touch-action: none; -webkit-user-select: none; user-select: none; } .Track { width: 100%; height: 0.25rem; background-color: oklch(92.2% 0 0deg); -webkit-user-select: none; user-select: none; @media (prefers-color-scheme: dark) { background-color: oklch(26.9% 0 0deg); } } .Indicator { background-color: oklch(14.5% 0 0deg); -webkit-user-select: none; user-select: none; @media (prefers-color-scheme: dark) { background-color: white; } } .Thumb { box-sizing: border-box; width: 1rem; height: 1rem; border: 1px solid oklch(14.5% 0 0deg); background-color: white; -webkit-user-select: none; user-select: none; @media (prefers-color-scheme: dark) { border: 1px solid white; background-color: oklch(14.5% 0 0deg); } &:has(:focus-visible) { outline: 2px solid oklch(14.5% 0 0deg); outline-offset: 2px; @media (prefers-color-scheme: dark) { outline-color: white; } } } ``` ```tsx /* index.tsx */ import { Slider } from '@base-ui/react/slider'; import styles from './index.module.css'; export default function RangeSlider() { return ( <Slider.Root defaultValue={[25, 45]}> <Slider.Control className={styles.Control}> <Slider.Track className={styles.Track}> <Slider.Indicator className={styles.Indicator} /> <Slider.Thumb index={0} aria-label="Minimum value" className={styles.Thumb} /> <Slider.Thumb index={1} aria-label="Maximum value" className={styles.Thumb} /> </Slider.Track> </Slider.Control> </Slider.Root> ); } ``` ### Thumb alignment Set `thumbAlignment="edge"` to inset the thumb such that its edge aligns with the edge of the control when the value is at `min` or `max`, without overflowing the control like the default `"center"` alignment. A client-only alternative `thumbAlignment="edge-client-only"` can be used to reduce bundle size but only renders after React hydration. ## Demo ### Tailwind This example shows how to implement the component using Tailwind CSS. ```tsx /* index.tsx */ import { Slider } from '@base-ui/react/slider'; export default function EdgeAlignedThumb() { return ( <Slider.Root thumbAlignment="edge" defaultValue={25}> <Slider.Control className="flex w-56 touch-none items-center py-3 select-none"> <Slider.Track className="h-1 w-full bg-neutral-200 select-none dark:bg-neutral-800"> <Slider.Indicator className="bg-neutral-950 select-none dark:bg-white" /> <Slider.Thumb aria-label="Volume" className="size-4 border border-neutral-950 bg-white select-none has-[:focus-visible]:outline-2 has-[:focus-visible]:outline-offset-2 has-[:focus-visible]:outline-neutral-950 dark:has-[:focus-visible]:outline-white dark:border-white dark:bg-neutral-950" /> </Slider.Track> </Slider.Control> </Slider.Root> ); } ``` ### CSS Modules This example shows how to implement the component using CSS Modules. ```css /* index.module.css */ .Control { box-sizing: border-box; display: flex; align-items: center; width: 14rem; padding-block: 0.75rem; touch-action: none; -webkit-user-select: none; user-select: none; } .Track { width: 100%; height: 0.25rem; background-color: oklch(92.2% 0 0deg); -webkit-user-select: none; user-select: none; @media (prefers-color-scheme: dark) { background-color: oklch(26.9% 0 0deg); } } .Indicator { background-color: oklch(14.5% 0 0deg); -webkit-user-select: none; user-select: none; @media (prefers-color-scheme: dark) { background-color: white; } } .Thumb { box-sizing: border-box; width: 1rem; height: 1rem; border: 1px solid oklch(14.5% 0 0deg); background-color: white; -webkit-user-select: none; user-select: none; @media (prefers-color-scheme: dark) { border: 1px solid white; background-color: oklch(14.5% 0 0deg); } &:has(:focus-visible) { outline: 2px solid oklch(14.5% 0 0deg); outline-offset: 2px; @media (prefers-color-scheme: dark) { outline-color: white; } } } ``` ```tsx /* index.tsx */ import { Slider } from '@base-ui/react/slider'; import styles from './index.module.css'; export default function EdgeAlignedThumb() { return ( <Slider.Root thumbAlignment="edge" defaultValue={25}> <Slider.Control className={styles.Control}> <Slider.Track className={styles.Track}> <Slider.Indicator className={styles.Indicator} /> <Slider.Thumb aria-label="Volume" className={styles.Thumb} /> </Slider.Track> </Slider.Control> </Slider.Root> ); } ``` ### Labeling a slider A single-thumb slider without a visible label (such as a volume control) can be labeled using `aria-label` on `<Slider.Thumb>`: ```tsx title="Slider with invisible label" <Slider.Root> <Slider.Control> <Slider.Track> <Slider.Indicator /> {/* @highlight */} <Slider.Thumb aria-label="Volume" /> </Slider.Track> </Slider.Control> </Slider.Root> ``` A visible label can be created using `<Slider.Label>`: ```tsx title="Slider with visible label" <Slider.Root> {/* @highlight */} <Slider.Label>Volume</Slider.Label> <Slider.Control> <Slider.Track> <Slider.Indicator /> <Slider.Thumb /> </Slider.Track> </Slider.Control> </Slider.Root> ``` For a multi-thumb range slider with a visible label, add `aria-label` on each `<Slider.Thumb>` to distinguish them: ```tsx title="Labeling multi-thumb range sliders" <Slider.Root defaultValue={[25, 75]}> <Slider.Label>Price range</Slider.Label> <Slider.Control> <Slider.Track> <Slider.Indicator /> {/* @highlight-start */} <Slider.Thumb index={0} aria-label="Minimum price" /> <Slider.Thumb index={1} aria-label="Maximum price" /> {/* @highlight-end */} </Slider.Track> </Slider.Control> </Slider.Root> ``` ### Vertical Set `orientation="vertical"` on `<Slider.Root>` to build a vertical slider. ## Demo ### Tailwind This example shows how to implement the component using Tailwind CSS. ```tsx /* index.tsx */ import { Slider } from '@base-ui/react/slider'; export default function VerticalSlider() { return ( <Slider.Root orientation="vertical" defaultValue={35}> <Slider.Control className="flex touch-none select-none data-[orientation=vertical]:h-32 data-[orientation=vertical]:px-3"> <Slider.Track className="bg-neutral-200 select-none dark:bg-neutral-800 data-[orientation=vertical]:h-full data-[orientation=vertical]:w-1"> <Slider.Indicator className="bg-neutral-950 select-none dark:bg-white" /> <Slider.Thumb aria-label="Volume" className="size-4 border border-neutral-950 bg-white select-none has-[:focus-visible]:outline-2 has-[:focus-visible]:outline-offset-2 has-[:focus-visible]:outline-neutral-950 dark:has-[:focus-visible]:outline-white dark:border-white dark:bg-neutral-950" /> </Slider.Track> </Slider.Control> </Slider.Root> ); } ``` ### CSS Modules This example shows how to implement the component using CSS Modules. ```css /* index.module.css */ .Control { box-sizing: border-box; display: flex; touch-action: none; -webkit-user-select: none; user-select: none; &[data-orientation='vertical'] { height: 8rem; padding-inline: 0.75rem; } } .Track { background-color: oklch(92.2% 0 0deg); -webkit-user-select: none; user-select: none; @media (prefers-color-scheme: dark) { background-color: oklch(26.9% 0 0deg); } &[data-orientation='vertical'] { height: 100%; width: 0.25rem; } } .Indicator { background-color: oklch(14.5% 0 0deg); -webkit-user-select: none; user-select: none; @media (prefers-color-scheme: dark) { background-color: white; } } .Thumb { box-sizing: border-box; width: 1rem; height: 1rem; border: 1px solid oklch(14.5% 0 0deg); background-color: white; -webkit-user-select: none; user-select: none; @media (prefers-color-scheme: dark) { border: 1px solid white; background-color: oklch(14.5% 0 0deg); } &:has(:focus-visible) { outline: 2px solid oklch(14.5% 0 0deg); outline-offset: 2px; @media (prefers-color-scheme: dark) { outline-color: white; } } } ``` ```tsx /* index.tsx */ import { Slider } from '@base-ui/react/slider'; import styles from './index.module.css'; export default function VerticalSlider() { return ( <Slider.Root orientation="vertical" defaultValue={35}> <Slider.Control className={styles.Control}> <Slider.Track className={styles.Track}> <Slider.Indicator className={styles.Indicator} /> <Slider.Thumb aria-label="Volume" className={styles.Thumb} /> </Slider.Track> </Slider.Control> </Slider.Root> ); } ``` ### Form integration To use a slider in a form, pass the slider `name` to `<Slider.Root>`: ```tsx title="Using Slider in a form" <Form> {/* @highlight */} <Slider.Root name="volume"> <Slider.Label>Volume</Slider.Label> <Slider.Control> <Slider.Track> <Slider.Indicator /> <Slider.Thumb /> </Slider.Track> </Slider.Control> </Slider.Root> </Form> ``` For grouped multi-thumb range sliders in forms, [Fieldset](/react/components/fieldset.md) can provide the shared visible label while each thumb keeps its own `aria-label`: ```tsx title="Using Fieldset with a multi-thumb slider" <Field.Root> {/* @highlight-start */} <Fieldset.Root render={<Slider.Root defaultValue={[25, 75]} />}> <Fieldset.Legend>Price range</Fieldset.Legend> {/* @highlight-end */} <Slider.Control> <Slider.Track> <Slider.Indicator /> {/* @highlight-start */} <Slider.Thumb index={0} aria-label="Minimum price" /> <Slider.Thumb index={1} aria-label="Maximum price" /> {/* @highlight-end */} </Slider.Track> </Slider.Control> </Fieldset.Root> </Field.Root> ``` ## API reference ### Root Groups all parts of the slider. Renders a `<div>` element. **Root Props:** | Prop | Type | Default | Description | | :--------------------- | :---------------------------------------------------------------------------------------- | :------------- | :-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | name | `string` | - | Identifies the field when a form is submitted. | | defaultValue | `number \| number[]` | - | The uncontrolled value of the slider when it's initially rendered. To render a controlled slider, use the `value` prop instead. | | value | `number \| number[]` | - | The value of the slider.&#xA;For ranged sliders, provide an array with two values. | | onValueChange | `((value: number \| number[], eventDetails: Slider.Root.ChangeEventDetails) => void)` | - | Callback function that is fired when the slider's value changed.&#xA;You can pull out the new value by accessing `event.target.value` (any). The `eventDetails.reason` indicates what triggered the change: `'input-change'` when the hidden range input emits a change event (for example, via form integration)`'track-press'` when the control track is pressed`'drag'` while dragging a thumb`'keyboard'` for keyboard input`'none'` when the change is triggered without a specific interaction | | onValueCommitted | `((value: number \| number[], eventDetails: Slider.Root.CommitEventDetails) => void)` | - | Callback function that is fired when a value change is committed.&#xA;Does not fire if the value did not change, or if the change was canceled.&#xA;**Warning**: This is a generic event, not a change event. The `eventDetails.reason` indicates what triggered the commit: `'drag'` while dragging a thumb`'track-press'` when the control track is pressed`'keyboard'` for keyboard input`'input-change'` when the hidden range input emits a change event (for example, via form integration)`'none'` when the commit occurs without a specific interaction | | form | `string` | - | Identifies the form that owns the slider inputs.&#xA;Useful when the slider is rendered outside the form. | | locale | `Intl.LocalesArgument` | - | The locale used by `Intl.NumberFormat` when formatting the value.&#xA;Defaults to the user's runtime locale. | | thumbAlignment | `'center' \| 'edge' \| 'edge-client-only'` | `'center'` | How the thumb(s) are aligned relative to `Slider.Control` when the value is at `min` or `max`: `center`: The center of the thumb is aligned with the control edge`edge`: The thumb is inset within the control such that its edge is aligned with the control edge`edge-client-only`: Same as `edge` but renders after React hydration on the client, reducing bundle size in return | | thumbCollisionBehavior | `'push' \| 'swap' \| 'none'` | `'push'` | Controls how thumbs behave when they collide during pointer interactions. `'push'` (default): Thumbs push each other without restoring their previous positions when dragged back.`'swap'`: Thumbs swap places when dragged past each other.`'none'`: Thumbs cannot move past each other; excess movement is ignored. | | step | `number` | `1` | The granularity with which the slider can step through values. (A "discrete" slider.)&#xA;The `min` prop serves as the origin for the valid values.&#xA;We recommend (max - min) to be evenly divisible by the step. | | largeStep | `number` | `10` | The granularity with which the slider can step through values when using Page Up/Page Down or Shift + Arrow Up/Arrow Down. | | minStepsBetweenValues | `number` | `0` | The minimum steps between values in a range slider. | | min | `number` | `0` | The minimum allowed value of the slider.&#xA;Should not be equal to max. | | max | `number` | `100` | The maximum allowed value of the slider.&#xA;Should not be equal to min. | | format | `Intl.NumberFormatOptions` | - | Options to format the input value. | | disabled | `boolean` | `false` | Whether the slider should ignore user interaction. | | orientation | `Orientation` | `'horizontal'` | The component orientation. | | className | `string \| ((state: Slider.Root.State) => string \| undefined)` | - | CSS class applied to the element, or a function that&#xA;returns a class based on the component's state. | | style | `React.CSSProperties \| ((state: Slider.Root.State) => React.CSSProperties \| undefined)` | - | Style applied to the element, or a function that&#xA;returns a style object based on the component's state. | | render | `ReactElement \| ((props: HTMLProps, state: Slider.Root.State) => ReactElement)` | - | Allows you to replace the component's HTML element&#xA;with a different tag, or compose it with another component. Accepts a `ReactElement` or a function that returns the element to render. | **Root Data Attributes:** | Attribute | Type | Description | | :--------------- | :--------------------------- | :--------------------------------------------------------------------------- | | data-dragging | - | Present while the user is dragging. | | data-orientation | `'horizontal' \| 'vertical'` | Indicates the orientation of the slider. | | data-disabled | - | Present when the slider is disabled. | | data-valid | - | Present when the slider is in a valid state (when wrapped in Field.Root). | | data-invalid | - | Present when the slider is in an invalid state (when wrapped in Field.Root). | | data-dirty | - | Present when the slider's value has changed (when wrapped in Field.Root). | | data-touched | - | Present when the slider has been touched (when wrapped in Field.Root). | | data-focused | - | Present when the slider is focused (when wrapped in Field.Root). | ### Root.Props Re-export of [Root](/react/components/slider.md) props. ### Root.State ```typescript type SliderRootState = { /** The index of the active thumb. */ activeThumbIndex: number; /** Whether the component should ignore user interaction. */ disabled: boolean; /** Whether the thumb is currently being dragged. */ dragging: boolean; /** The maximum value. */ max: number; /** The minimum value. */ min: number; /** * The minimum steps between values in a range slider. * @default 0 */ minStepsBetweenValues: number; /** The component orientation. */ orientation: Orientation; /** * The step increment of the slider when incrementing or decrementing. It will snap * to multiples of this value. Decimal values are supported. * @default 1 */ step: number; /** The raw number value of the slider. */ values: number[]; /** Whether the field has been touched. */ touched: boolean; /** Whether the field value has changed from its initial value. */ dirty: boolean; /** Whether the field is valid. */ valid: boolean | null; /** Whether the field has a value. */ filled: boolean; /** Whether the field is focused. */ focused: boolean; }; ``` ### Root.ChangeEventReason ```typescript type SliderRootChangeEventReason = 'input-change' | 'track-press' | 'drag' | 'keyboard' | 'none'; ``` ### Root.ChangeEventDetails ```typescript type SliderRootChangeEventDetails = ( | { reason: 'none'; event: Event } | { reason: 'input-change'; event: Event | InputEvent } | { reason: 'track-press'; event: PointerEvent | MouseEvent | TouchEvent } | { reason: 'drag'; event: PointerEvent | TouchEvent } | { reason: 'keyboard'; event: KeyboardEvent } ) & { /** Cancels Base UI from handling the event. */ cancel: () => void; /** Allows the event to propagate in cases where Base UI will stop the propagation. */ allowPropagation: () => void; /** Indicates whether the event has been canceled. */ isCanceled: boolean; /** Indicates whether the event is allowed to propagate. */ isPropagationAllowed: boolean; /** The element that triggered the event, if applicable. */ trigger: Element | undefined; /** The index of the active thumb at the time of the change. */ activeThumbIndex: number; }; ``` ### Root.CommitEventReason ```typescript type SliderRootCommitEventReason = 'input-change' | 'track-press' | 'drag' | 'keyboard' | 'none'; ``` ### Root.CommitEventDetails ```typescript type SliderRootCommitEventDetails = | { reason: 'none'; event: Event } | { reason: 'input-change'; event: Event | InputEvent } | { reason: 'track-press'; event: PointerEvent | MouseEvent | TouchEvent } | { reason: 'drag'; event: PointerEvent | TouchEvent } | { reason: 'keyboard'; event: KeyboardEvent }; ``` ### Value Displays the current value of the slider as text. Renders an `<output>` element. **Value Props:** | Prop | Type | Default | Description | | :-------- | :----------------------------------------------------------------------------------------- | :------ | :-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | children | `((formattedValues: string[], values: number[]) => React.ReactNode) \| null` | - | - | | className | `string \| ((state: Slider.Value.State) => string \| undefined)` | - | CSS class applied to the element, or a function that&#xA;returns a class based on the component's state. | | style | `React.CSSProperties \| ((state: Slider.Value.State) => React.CSSProperties \| undefined)` | - | Style applied to the element, or a function that&#xA;returns a style object based on the component's state. | | render | `ReactElement \| ((props: HTMLProps, state: Slider.Value.State) => ReactElement)` | - | Allows you to replace the component's HTML element&#xA;with a different tag, or compose it with another component. Accepts a `ReactElement` or a function that returns the element to render. | **Value Data Attributes:** | Attribute | Type | Description | | :--------------- | :--------------------------- | :--------------------------------------------------------------------------- | | data-dragging | - | Present while the user is dragging. | | data-orientation | `'horizontal' \| 'vertical'` | Indicates the orientation of the slider. | | data-disabled | - | Present when the slider is disabled. | | data-valid | - | Present when the slider is in a valid state (when wrapped in Field.Root). | | data-invalid | - | Present when the slider is in an invalid state (when wrapped in Field.Root). | | data-dirty | - | Present when the slider's value has changed (when wrapped in Field.Root). | | data-touched | - | Present when the slider has been touched (when wrapped in Field.Root). | | data-focused | - | Present when the slider is focused (when wrapped in Field.Root). | ### Value.Props Re-export of [Value](/react/components/slider.md) props. ### Value.State ```typescript type SliderValueState = { /** The index of the active thumb. */ activeThumbIndex: number; /** Whether the component should ignore user interaction. */ disabled: boolean; /** Whether the thumb is currently being dragged. */ dragging: boolean; /** The maximum value. */ max: number; /** The minimum value. */ min: number; /** * The minimum steps between values in a range slider. * @default 0 */ minStepsBetweenValues: number; /** The component orientation. */ orientation: Orientation; /** * The step increment of the slider when incrementing or decrementing. It will snap * to multiples of this value. Decimal values are supported. * @default 1 */ step: number; /** The raw number value of the slider. */ values: number[]; /** Whether the field has been touched. */ touched: boolean; /** Whether the field value has changed from its initial value. */ dirty: boolean; /** Whether the field is valid. */ valid: boolean | null; /** Whether the field has a value. */ filled: boolean; /** Whether the field is focused. */ focused: boolean; }; ``` ### Indicator Visualizes the current value of the slider. Renders a `<div>` element. **Indicator Props:** | Prop | Type | Default | Description | | :-------- | :--------------------------------------------------------------------------------------------- | :------ | :-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | className | `string \| ((state: Slider.Indicator.State) => string \| undefined)` | - | CSS class applied to the element, or a function that&#xA;returns a class based on the component's state. | | style | `React.CSSProperties \| ((state: Slider.Indicator.State) => React.CSSProperties \| undefined)` | - | Style applied to the element, or a function that&#xA;returns a style object based on the component's state. | | render | `ReactElement \| ((props: HTMLProps, state: Slider.Indicator.State) => ReactElement)` | - | Allows you to replace the component's HTML element&#xA;with a different tag, or compose it with another component. Accepts a `ReactElement` or a function that returns the element to render. | **Indicator Data Attributes:** | Attribute | Type | Description | | :--------------- | :--------------------------- | :--------------------------------------------------------------------------- | | data-dragging | - | Present while the user is dragging. | | data-orientation | `'horizontal' \| 'vertical'` | Indicates the orientation of the slider. | | data-disabled | - | Present when the slider is disabled. | | data-valid | - | Present when the slider is in a valid state (when wrapped in Field.Root). | | data-invalid | - | Present when the slider is in an invalid state (when wrapped in Field.Root). | | data-dirty | - | Present when the slider's value has changed (when wrapped in Field.Root). | | data-touched | - | Present when the slider has been touched (when wrapped in Field.Root). | | data-focused | - | Present when the slider is focused (when wrapped in Field.Root). | ### Indicator.Props Re-export of [Indicator](/react/components/slider.md) props. ### Indicator.State ```typescript type SliderIndicatorState = { /** The index of the active thumb. */ activeThumbIndex: number; /** Whether the component should ignore user interaction. */ disabled: boolean; /** Whether the thumb is currently being dragged. */ dragging: boolean; /** The maximum value. */ max: number; /** The minimum value. */ min: number; /** * The minimum steps between values in a range slider. * @default 0 */ minStepsBetweenValues: number; /** The component orientation. */ orientation: Orientation; /** * The step increment of the slider when incrementing or decrementing. It will snap * to multiples of this value. Decimal values are supported. * @default 1 */ step: number; /** The raw number value of the slider. */ values: number[]; /** Whether the field has been touched. */ touched: boolean; /** Whether the field value has changed from its initial value. */ dirty: boolean; /** Whether the field is valid. */ valid: boolean | null; /** Whether the field has a value. */ filled: boolean; /** Whether the field is focused. */ focused: boolean; }; ``` ### Track Contains the slider indicator and represents the entire range of the slider. Renders a `<div>` element. **Track Props:** | Prop | Type | Default | Description | | :-------- | :----------------------------------------------------------------------------------------- | :------ | :-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | className | `string \| ((state: Slider.Track.State) => string \| undefined)` | - | CSS class applied to the element, or a function that&#xA;returns a class based on the component's state. | | style | `React.CSSProperties \| ((state: Slider.Track.State) => React.CSSProperties \| undefined)` | - | Style applied to the element, or a function that&#xA;returns a style object based on the component's state. | | render | `ReactElement \| ((props: HTMLProps, state: Slider.Track.State) => ReactElement)` | - | Allows you to replace the component's HTML element&#xA;with a different tag, or compose it with another component. Accepts a `ReactElement` or a function that returns the element to render. | **Track Data Attributes:** | Attribute | Type | Description | | :--------------- | :--------------------------- | :--------------------------------------------------------------------------- | | data-dragging | - | Present while the user is dragging. | | data-orientation | `'horizontal' \| 'vertical'` | Indicates the orientation of the slider. | | data-disabled | - | Present when the slider is disabled. | | data-valid | - | Present when the slider is in a valid state (when wrapped in Field.Root). | | data-invalid | - | Present when the slider is in an invalid state (when wrapped in Field.Root). | | data-dirty | - | Present when the slider's value has changed (when wrapped in Field.Root). | | data-touched | - | Present when the slider has been touched (when wrapped in Field.Root). | | data-focused | - | Present when the slider is focused (when wrapped in Field.Root). | ### Track.Props Re-export of [Track](/react/components/slider.md) props. ### Track.State ```typescript type SliderTrackState = { /** The index of the active thumb. */ activeThumbIndex: number; /** Whether the component should ignore user interaction. */ disabled: boolean; /** Whether the thumb is currently being dragged. */ dragging: boolean; /** The maximum value. */ max: number; /** The minimum value. */ min: number; /** * The minimum steps between values in a range slider. * @default 0 */ minStepsBetweenValues: number; /** The component orientation. */ orientation: Orientation; /** * The step increment of the slider when incrementing or decrementing. It will snap * to multiples of this value. Decimal values are supported. * @default 1 */ step: number; /** The raw number value of the slider. */ values: number[]; /** Whether the field has been touched. */ touched: boolean; /** Whether the field value has changed from its initial value. */ dirty: boolean; /** Whether the field is valid. */ valid: boolean | null; /** Whether the field has a value. */ filled: boolean; /** Whether the field is focused. */ focused: boolean; }; ``` ### Thumb The draggable part of the slider at the tip of the indicator. Renders a `<div>` element and a nested `<input type="range">`. **Thumb Props:** | Prop | Type | Default | Description | | :--------------- | :----------------------------------------------------------------------------------------- | :------ | :----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | aria-valuetext | `string` | - | A string value forwarded to the [`aria-valuetext`](https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/Reference/Attributes/aria-valuetext) attribute of the `input`.&#xA;Ignored when `getAriaValueText` is provided. | | getAriaLabel | `((index: number) => string) \| null` | - | A function which returns a string value for the [`aria-label`](https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/Reference/Attributes/aria-label) attribute of the `input`. | | getAriaValueText | `((formattedValue: string, value: number, index: number) => string) \| null` | - | A function