Slider is a form control that allows users to select a numeric value within a defined range by dragging a thumb along a track.
Installation
yarn add @twilio-paste/slider @twilio-paste/label @twilio-paste/help-text
Usage
import { Slider } from '@twilio-paste/slider';
import { Label } from '@twilio-paste/label';
const MyComponent = () => {
const [value, setValue] = React.useState(50);
return (
<>
<Label htmlFor="volume">Volume</Label>
<Slider
id="volume"
value={value}
onChange={(newValue) => setValue(newValue)}
/>
</>
);
};
Props
Must provide an id to match with a label.
ID of the element that labels the slider (if not using htmlFor with Label).
ID of the help text element describing the slider.
The smallest number in the slider range.
The largest number in the slider range.
The incremented value as you drag along the range.
The current selected value (controlled component).
Fired on every change as the thumb is dragged along the track.
Fired at the end of the dragging event once.
Shows error styling on the slider.
Hides the min and max values that appear over the slider.
Used to adjust how the numbers are rendered and interpreted.
i18nMaxRangeLabel
string
default:"'Maximum value:'"
Internationalization for the max range label.
i18nMinRangeLabel
string
default:"'Minimum value:'"
Internationalization for the min range label.
Internationalization for the value label.
Overrides the default element name for customization.
Examples
Basic Slider
import { Slider } from '@twilio-paste/slider';
import { Label } from '@twilio-paste/label';
const [volume, setVolume] = React.useState(50);
<>
<Label htmlFor="volume-slider">Volume: {volume}%</Label>
<Slider
id="volume-slider"
value={volume}
onChange={setVolume}
minValue={0}
maxValue={100}
/>
</>
With Custom Range
import { Slider } from '@twilio-paste/slider';
import { Label } from '@twilio-paste/label';
import { HelpText } from '@twilio-paste/help-text';
const [price, setPrice] = React.useState(500);
<>
<Label htmlFor="price">Maximum price: ${price}</Label>
<Slider
id="price"
value={price}
onChange={setPrice}
minValue={0}
maxValue={1000}
step={50}
/>
<HelpText>Select your budget range</HelpText>
</>
With Step Increments
import { Slider } from '@twilio-paste/slider';
import { Label } from '@twilio-paste/label';
const [rating, setRating] = React.useState(3);
<>
<Label htmlFor="rating">Rating: {rating} stars</Label>
<Slider
id="rating"
value={rating}
onChange={setRating}
minValue={1}
maxValue={5}
step={1}
/>
</>
Without Range Labels
import { Slider } from '@twilio-paste/slider';
import { Label } from '@twilio-paste/label';
const [opacity, setOpacity] = React.useState(0.5);
<>
<Label htmlFor="opacity">Opacity: {(opacity * 100).toFixed(0)}%</Label>
<Slider
id="opacity"
value={opacity}
onChange={setOpacity}
minValue={0}
maxValue={1}
step={0.1}
hideRangeLabels
/>
</>
With Number Formatting
import { Slider } from '@twilio-paste/slider';
import { Label } from '@twilio-paste/label';
const [price, setPrice] = React.useState(1000);
const currencyFormatter = new Intl.NumberFormat('en-US', {
style: 'currency',
currency: 'USD',
minimumFractionDigits: 0,
});
<>
<Label htmlFor="budget">
Budget: {currencyFormatter.format(price)}
</Label>
<Slider
id="budget"
value={price}
onChange={setPrice}
minValue={0}
maxValue={5000}
step={100}
numberFormatter={currencyFormatter}
/>
</>
Disabled Slider
import { Slider } from '@twilio-paste/slider';
import { Label } from '@twilio-paste/label';
<>
<Label htmlFor="disabled-slider" disabled>
Brightness
</Label>
<Slider
id="disabled-slider"
value={75}
disabled
/>
</>
With Error State
import { Slider } from '@twilio-paste/slider';
import { Label } from '@twilio-paste/label';
import { HelpText } from '@twilio-paste/help-text';
const [temperature, setTemperature] = React.useState(95);
const hasError = temperature > 90;
<>
<Label htmlFor="temp" required>
Temperature: {temperature}°F
</Label>
<Slider
id="temp"
value={temperature}
onChange={setTemperature}
minValue={60}
maxValue={100}
hasError={hasError}
/>
{hasError && (
<HelpText variant="error">
Temperature must not exceed 90°F
</HelpText>
)}
</>
With onChange and onChangeEnd
import { Slider } from '@twilio-paste/slider';
import { Label } from '@twilio-paste/label';
const [value, setValue] = React.useState(50);
const [committed, setCommitted] = React.useState(50);
const handleChange = (newValue: number) => {
setValue(newValue);
// Update UI immediately while dragging
};
const handleChangeEnd = (finalValue: number) => {
setCommitted(finalValue);
// Make API call or save to database
console.log('Final value:', finalValue);
};
<>
<Label htmlFor="brightness">
Brightness: {value} (Saved: {committed})
</Label>
<Slider
id="brightness"
value={value}
onChange={handleChange}
onChangeEnd={handleChangeEnd}
/>
</>
Accessibility
- Built on WAI-ARIA Slider pattern
- Fully keyboard accessible:
- Arrow keys adjust value by step amount
- Home/End keys jump to min/max values
- Page Up/Down for larger increments
- Screen readers announce current value and range
- Must be paired with a Label using matching
id and htmlFor
- Min and max values are announced to screen readers
- Current value is continuously announced as it changes
- Disabled state is properly communicated
Best Practices
- Use Slider for selecting approximate values within a range
- For precise numeric input, use Input with type=“number” instead
- Always provide a visible label showing the current value
- Set appropriate min, max, and step values for your use case
- Display the current value near the slider for clarity
- Use
onChangeEnd for expensive operations like API calls
- Use
onChange for immediate UI updates
- Show units in the label (%, $, degrees, etc.)
- Consider using number formatting for currency or percentages
- Set reasonable ranges - very large ranges can be hard to use
- For very precise values, provide an alternative input method
When to Use Slider
Use Slider when:
- The value is relative or approximate
- Users benefit from seeing the range
- Immediate visual feedback is helpful
- The value has clear minimum and maximum bounds
Don’t use Slider when:
- Precise values are required
- The range is very large (e.g., 1-10000)
- Users need to enter specific numbers
- Screen space is limited