import { Slider } from '@uhg-abyss/web/ui/Slider';() => { const [value, setValue] = React.useState(0);
return ( <Slider step={10} label="Sandbox Slider" value={value} onChange={(e) => setValue(e)} /> );};useForm (recommended)
Using useForm and FormProvider simplifies form management by providing out-of-the-box validation, form state handling, and performance optimizations, leveraging the power of react-hook-form.
useState
Using the useState hook gets values from the component state.
Label area
Use the label prop to display the required label above the slider. Props subText and helper are optional to further customize the label area of the slider.
Prop subText be used to provide hint text below the label of the slider.
Use the helper prop to display a help icon next to the label. Simply passing a string value will render the default helper, a Tooltip containing that string. The helper can be customized by passing in a node. It is recommended to use either a Tooltip or a Popover. See When should I use a Tooltip vs. a Popover? for more information on best practices regarding the two.
Additionally, the isRequired prop can be used to add an asterisk next to the label. Since the slider will always have a value, defaulting to the minimum, there is no validation necessary. Therefore, isRequired can be used whether using useForm or useState, which is different behavior than other form components.
Min & max values
Use the minValue and maxValue properties to set the minimum and maximum values the slider can equal. By default, the range is set to 0 and 100.
Step
To make a discrete slider, the input snaps to specific values, decided by the step prop. Use the step property to set the number that the value will increment/decrement on change. Default is 1.
Marks config
The Slider marks can be customized with marksConfig. The type is as follows:
{ showMarks?: 'none' | 'endpoints' | 'step'; marks?: Array<{ value: number; label: string }>; customLabel?: (value: number) => string;}showMarks can be set to none, endpoints, or step. If set to endpoints, marks will only be shown at the minimum and maximum values. If set to step (the default), marks will be shown at every step. If set to none, no marks will be shown.
marks can be used to provide custom marks at specific values, which is useful if you do not want any of the showMarks options. Each mark should be an object with a value and a label.
Track tooltip config
The track tooltip can be customized with tooltipConfig. The type is as follows:
{ alwaysOn?: boolean; showOnHover?: boolean; showOnDrag?: boolean; customLabel?: (value: number) => string;}Use alwaysOn to keep the popover always displayed. showOnHover can be used to display the tooltip when the user hovers over the thumb. showOnDrag can be used to display the tooltip when the user drags the thumb.
Use customLabel to set a custom label for the tooltip.
Disabled
Use the isDisabled property to disable the slider.
Form input customization
Similar to TextInput, the Slider form input can be customized by providing a prefix or suffix. Note that not all props for TextInput are applicable to Slider.
Slider Props
| Name | Type | Default | Required | Description |
|---|---|---|---|---|
className | string | - | - | CSS class name to apply to each element within the component |
css | Abyss.CSSProperties | Partial<Record<`abyss-${T}`, Abyss.CSSProperties>> | - | - | Object containing CSS styling to apply; uses the classes listed in the "Integration" tab of the component's documentation |
data-testid | string | - | - | Suffix used to create a unique ID used for automated testing |
disableDefaultProviderProps | boolean | false | - | If set to true, the component will not use the DefaultPropsProvider values. If you aren’t using the DefaultPropsProvider, this prop can be ignored. |
helper | React.ReactNode | - | - | Helper element next to label |
highlighted | boolean | false | - | If true, the input field will be highlighted |
isDisabled | boolean | false | - | If true, the input will be disabled |
isRequired | boolean | - | - | Whether the input is required |
label | string | - | The label for the input | |
marksConfig | MarksConfig | '{showMarks='step'}' | - | Object to configure the marks on the slider |
maxValue | number | 100 | - | The maximum value of the slider |
minValue | number | 0 | - | The minimum value of the slider |
model | never | string | - | - | model should not exist in useState mode. Model name for form validation. Only used when in a FormProvider. |
onBlur | () => void | - | - | Callback function executed when the slider is blurred |
onChange | (value: number) => void | - | - | Callback function executed when the slider value changes |
onChangeEnd | (newValue: number) => void | - | - | Callback fired when the slider is no longer being dragged |
onKeyDown | (event: React.KeyboardEvent<Element>) => void | - | - | Callback for key down events |
onPaste | (event: React.ClipboardEvent<Element>) => void | - | - | Callback for paste events |
precision | number | - | - | The precision for the slider value |
prefix | string | - | - | Content to display before the slider input |
step | number | 1 | - | The step size for the slider |
subText | string | - | - | Additional descriptive text for the slider |
suffix | string | - | - | Content to display after the slider input |
thumbLabel | string | - | - | Label for the thumb |
tooltipConfig | TooltipConfig | - | - | Object to configure the track tooltip |
validators | never | RegisterOptions | - | - | validators should not exist in useState mode. Validators for the input. Only used when in a FormProvider. |
value | ValueType | never | - | - | The value of the input. Only used when not in a FormProvider. value should not exist in useForm mode. |
width | string | number | '100%' | - | The width of the slider |
Slider Classes
| Class Name | Description |
|---|---|
| .abyss-slider-root | Slider root element |
| .abyss-slider-label | Slider label element |
| .abyss-slider-input | Slider TextInput element |
| .abyss-slider-descriptor | Slider form descriptors element |
| .abyss-slider-form-root | Slider form root container |
| .abyss-slider-upper-container | Slider upper container |
| .abyss-slider-sub-text | Slider sub text |
| .abyss-slider-input-wrapper | Slider input wrapper |
| .abyss-slider-input-wrapper-container | Slider input wrapper container |
| .abyss-slider-input-prefix | Slider input prefix |
| .abyss-slider-input-suffix | Slider input suffix |
| .abyss-slider-track-wrapper | Slider track outer wrapper |
| .abyss-slider-track-container | Slider track container |
| .abyss-slider-track-filled | Slider filled bar |
| .abyss-slider-track | Slider track background |
| .abyss-slider-marks | Slider marks container |
| .abyss-slider-track-filler | Slider track filler (legacy/compat) |
| .abyss-slider-thumb | Slider thumb element |
| .abyss-slider-thumb-tooltip | Slider thumb tooltip element |
| .abyss-slider-thumb-tooltip-label | Slider thumb tooltip label |
| .abyss-slider-thumb-arrow-container | Slider thumb tooltip arrow container |
| .abyss-slider-thumb-container | Slider thumb container element |
| .abyss-slider-mark-wrapper | Slider individual mark wrapper |
| .abyss-slider-tick-mark | Slider tick mark |
| .abyss-slider-mark-text | Slider mark label text |
| .abyss-slider-track-mark-wrapper | Slider track mark wrapper |
| .abyss-slider-track-marks | Slider track marks container |
| .abyss-slider-track-marks-text | Slider track marks text |
Slider's design merges a number entry field (HTML <input type="number"> announced as "spinbox") with an slider. From an accessibility perspective, having dual controls active to update a single value can be redundant, confusing, and unnecessary.
- For keyboard users, It adds an extra tab stop in the focus order and duplicate controls for the entering the same value
- For screen reader users, the redundant slider following the input box will be unexpected and particularly confusing
To simplify and address these issues, Slider's keyboard and screen reader interactions are restricted to the number entry field. All slider functionality and information have direct equivalents in then number field. This makes the visible "slider" redundant, so it is not directly accessed or announced.
The resulting changes are:
-
Keyboard experience: Only number/spinbox field receives keyboard focus
- Since it is tied to the slider thumb, sighted users will see slider updates and have equivalent control of it
-
Screen reader experience: The entire slider is hidden from screen readers (using
aria-hidden="true")- This suppresses any announcement of the thumb and any index marks
- The input field implementation using
<input type="number">eliminates the ability to usearia-textvalue - As result, any prefix or suffix settings to the field are added as part of the field label (using
aria-labelledby) which aligns as extended field sub-labels.
Keyboard Interactions
| Key | Description |
|---|---|
| Right Arrow: | Edit the number in the input field. |
| Up Arrow: | Increase the value of the slider form input by one step. |
| Down Arrow: | Decrease the value of the slider form input by one step. |
| Left Arrow: | Edit the number in the input field. |
| Home: | Set the value to the minimum. |
| End: | Set the value to the maximum. |
Component Tokens
Note: Click on the token row to copy the token to your clipboard.
Slider Tokens
| Token Name | Value | |
|---|---|---|
| slider.color.surface.track.fill.default | #196ECF | |
| slider.color.surface.track.fill.disabled | #CBCCCD | |
| slider.color.surface.track.end-point.default | #4B4D4F | |
| slider.color.surface.track.end-point.disabled | #CBCCCD | |
| slider.color.surface.scale.tick | #4B4D4F | |
| slider.color.surface.text.label.scale | #323334 | |
| slider.color.surface.handle.default | #196ECF | |
| slider.color.surface.handle.disabled | #CBCCCD | |
| slider.color.icon.handle | #FFFFFF | |
| slider.border-radius.all.handle | 500px | |
| slider.sizing.all.icon.handle | 24px | |
| slider.spacing.gap.horizontal.label-input | 40px | |
| slider.spacing.gap.vertical.scale | 4px | |
| slider.spacing.gap.vertical.container | 64px | |
| slider.spacing.gap.vertical.handle | 8px | |
| slider.spacing.gap.vertical.track-scale | 24px | |
| slider.spacing.padding.horizontal.scale | 16px |
Input Tokens
| Token Name | Value | |
|---|---|---|
| input.color.surface.field.default | #FFFFFF | |
| input.color.surface.field.highlighted | #E5F8FB | |
| input.color.surface.field.disabled | #F3F3F3 | |
| input.color.border.field.rest | #4B4D4F | |
| input.color.border.field.hover.default | #196ECF | |
| input.color.border.field.hover.error | #990000 | |
| input.color.border.field.hover.success | #007000 | |
| input.color.border.field.active.default | #004BA0 | |
| input.color.border.field.active.error | #990000 | |
| input.color.border.field.active.success | #007000 | |
| input.color.text.input | #4B4D4F | |
| input.color.text.hint | #4B4D4F | |
| input.color.text.required | #990000 | |
| input.color.icon.utility.rest | #4B4D4F | |
| input.color.icon.utility.hover | #323334 | |
| input.color.icon.utility.active | #000000 | |
| input.color.icon.content | #323334 | |
| input.border-radius.all.field | 4px | |
| input.border-width.all.field.default | 1px | |
| input.border-width.all.field.active | 3px | |
| input.sizing.all.icon | 20px | |
| input.spacing.gap.vertical.container | 8px | |
| input.spacing.gap.horizontal.field | 12px | |
| input.spacing.gap.horizontal.input-indicator | 2px | |
| input.spacing.gap.horizontal.prefix-input | 2px | |
| input.spacing.gap.horizontal.suffix-clear | 2px | |
| input.spacing.padding.all.focus-container | 2px | |
| input.spacing.padding.horizontal.field | 12px | |
| input.spacing.padding.left.field | 12px | |
| input.spacing.padding.right.focus-field | 44px |
Header Tokens
| Token Name | Value | |
|---|---|---|
| input-header.color.text.label | #4B4D4F | |
| input-header.color.text.hint | #4B4D4F | |
| input-header.color.icon.info.rest | #196ECF | |
| input-header.color.icon.info.hover | #004BA0 | |
| input-header.color.icon.info.active | #002677 | |
| input-header.sizing.all.icon | 24px | |
| input-header.spacing.gap.horizontal.container | 4px | |
| input-header.spacing.gap.horizontal.label | 4px | |
| input-header.spacing.gap.vertical.content | 4px | |
| input-header.spacing.padding.top.content | 2px |