Slider

Capture user feedback from a range of values
Import

Usage

20%
50%
80%
Type
Color
Size
xs
sm
md
lg
xl
Radius
xs
sm
md
lg
xl
import { Slider } from '@mantine/core';
function Demo() {
return (
<Slider
marks={[
{ value: 20, label: '20%' },
{ value: 50, label: '50%' },
{ value: 80, label: '80%' },
]}
/>
);
}

Controlled

By default, both Slider and RangeSlider are uncontrolled, add onChange and value props to make them controlled:

import { useState } from 'react';
import { Slider, RangeSlider } from '@mantine/core';
function Demo() {
const [value, setValue] = useState(40);
const [rangeValue, setRangeValue] = useState<[number, number]>([20, 80]);
return (
<>
<Slider value={value} onChange={setValue} />
<RangeSlider value={rangeValue} onChange={setRangeValue} />
</>
);
}

Disabled state

xs
sm
md
lg
xl
import { Slider, RangeSlider } from '@mantine/core';
function Demo() {
return (
<>
<Slider defaultValue={60} disabled />
<RangeSlider
disabled
defaultValue={[25, 75]}
marks={[
{ value: 0, label: 'xs' },
{ value: 25, label: 'sm' },
{ value: 50, label: 'md' },
{ value: 75, label: 'lg' },
{ value: 100, label: 'xl' },
]}
/>
</>
);
}

onChangeEnd

onChangeEnd callback is called when user stops dragging the slider or uses arrows:

onChange value: 50
onChangeEnd value: 50
import { useState } from 'react';
import { Slider, Text, Box } from '@mantine/core';
function Demo() {
const [value, setValue] = useState(50);
const [endValue, setEndValue] = useState(50);
return (
<Box maw={400} mx="auto">
<Slider value={value} onChange={setValue} onChangeEnd={setEndValue} />
<Text mt="md" size="sm">
onChange value: <b>{value}</b>
</Text>
<Text mt={5} size="sm">
onChangeEnd value: <b>{endValue}</b>
</Text>
</Box>
);
}

Control label

To change label behavior and appearance, set the following props:

  • label – formatter function, accepts value as an argument, set null to disable label, defaults to f => f
  • labelAlwaysOn – if true – label will always be displayed, by default label is visible only when user is dragging
  • labelTransition, labelTransitionDuration, labelTransitionTimingFunction – label uses Transition component to animate presence, you can choose any premade transition or create your own
No label
Formatted label
Label always visible
40
Custom label transition
import { Slider } from '@mantine/core';
function Demo() {
return (
<>
{/* Disable label */}
<Slider label={null} />
{/* Format label with function */}
<Slider label={(value) => `${value} °C`} />
{/* Always display label */}
<Slider labelAlwaysOn />
{/* Change label transition */}
<Slider
labelTransition="skew-down"
labelTransitionDuration={150}
labelTransitionTimingFunction="ease"
/>
</>
);
}

Min, max and step

Decimal step
Step matched with marks
xs
sm
md
lg
xl
import { Slider } from '@mantine/core';
// Configure marks to match step
const MARKS = [
{ value: 0, label: 'xs' },
{ value: 25, label: 'sm' },
{ value: 50, label: 'md' },
{ value: 75, label: 'lg' },
{ value: 100, label: 'xl' },
];
function Demo() {
return (
<>
{/* Set min, max and step props to replace default values */}
<Slider
defaultValue={5}
min={-10}
max={10}
label={(value) => value.toFixed(1)}
step={0.1}
precision={1}
styles={{ markLabel: { display: 'none' } }}
/>
<Slider
label={(val) => MARKS.find((mark) => mark.value === val).label}
defaultValue={50}
step={25}
marks={MARKS}
styles={{ markLabel: { display: 'none' } }}
/>
</>
);
}

Marks

Add any number of marks to slider by setting marks prop to an array of objects:

const marks = [
{ value: 20 }, // -> displays mark on slider track
{ value: 40, label: '40%' }, // -> adds mark label below slider track
];

Note that mark value is relative to slider value, not width:

20%
50%
80%
20%
50%
80%
import { Slider, RangeSlider } from '@mantine/core';
const marks = [
{ value: 20, label: '20%' },
{ value: 50, label: '50%' },
{ value: 80, label: '80%' },
];
function Demo() {
return (
<>
<Slider defaultValue={40} marks={[{ value: 10 }, { value: 40 }, { value: 95 }]} />
<Slider defaultValue={40} marks={marks} />
<RangeSlider defaultValue={[20, 80]} marks={marks} />
</>
);
}

Thumb size

import { Slider, RangeSlider } from '@mantine/core';
function Demo() {
return (
<>
<Slider thumbSize={14} defaultValue={20} />
<RangeSlider thumbSize={14} mt="xl" defaultValue={[20, 80]} />
</>
);
}

Thumb children

import { Slider, RangeSlider, rem } from '@mantine/core';
import { IconHeart, IconHeartBroken } from '@tabler/icons-react';
function Demo() {
return (
<>
<Slider
thumbChildren={<IconHeart size="1rem" />}
color="red"
label={null}
defaultValue={40}
thumbSize={26}
styles={{ thumb: { borderWidth: rem(2), padding: rem(3) } }}
/>
<RangeSlider
mt="xl"
styles={{ thumb: { borderWidth: rem(2), padding: rem(3) } }}
color="red"
label={null}
defaultValue={[20, 60]}
thumbSize={26}
thumbChildren={[<IconHeart size="1rem" key="1" />, <IconHeartBroken size="1rem" key="2" />]}
/>
</>
);
}

Scale

You can use the scale prop to represent the value on a different scale.

In the following demo, the value x represents the value 2^x. Increasing x by one increases the represented value by 2 to the power of x.

1 MB
1 MB
1 GB
import { RangeSlider, Slider, Stack } from '@mantine/core';
function Demo() {
function valueLabelFormat(value: number) {
const units = ['KB', 'MB', 'GB', 'TB'];
let unitIndex = 0;
let scaledValue = value;
while (scaledValue >= 1024 && unitIndex < units.length - 1) {
unitIndex += 1;
scaledValue /= 1024;
}
return `${scaledValue} ${units[unitIndex]}`;
}
return (
<Stack spacing="xl" p="xl">
<Slider
py="xl"
scale={(v) => 2 ** v}
step={1}
min={2}
max={30}
labelAlwaysOn
defaultValue={10}
label={valueLabelFormat}
/>
<RangeSlider
py="xl"
scale={(v) => 2 ** v}
step={1}
min={2}
max={30}
labelAlwaysOn
defaultValue={[10, 20]}
label={valueLabelFormat}
/>
</Stack>
);
}

Inverted

You can invert the track with the inverted prop:

import { RangeSlider, Slider } from '@mantine/core';
function Demo() {
return (
<>
<Slider inverted defaultValue={80} py="xl" />
<RangeSlider inverted defaultValue={[40, 80]} py="xl" />
</>
);
}

Styles API

You can change styles of any element in slider component with Styles API to match your design requirements:

20%
50%
80%
import { Slider, rem } from '@mantine/core';
const marks = [
{ value: 20, label: '20%' },
{ value: 50, label: '50%' },
{ value: 80, label: '80%' },
];
function Demo() {
return (
<Slider
defaultValue={40}
marks={marks}
labelTransition="fade"
size={2}
styles={(theme) => ({
track: {
backgroundColor:
theme.colorScheme === 'dark' ? theme.colors.dark[3] : theme.colors.blue[1],
},
mark: {
width: rem(6),
height: rem(6),
borderRadius: rem(6),
transform: `translateX(-${rem(3)}) translateY(-${rem(2)})`,
borderColor: theme.colorScheme === 'dark' ? theme.colors.dark[3] : theme.colors.blue[1],
},
markFilled: {
borderColor: theme.colors.blue[6],
},
markLabel: { fontSize: theme.fontSizes.xs, marginBottom: rem(5), marginTop: 0 },
thumb: {
height: rem(16),
width: rem(16),
backgroundColor: theme.white,
borderWidth: rem(1),
boxShadow: theme.shadows.sm,
},
})}
/>
);
}

Vertical slider

Slider and RangeSlider do not provide vertical orientation as it is very rarely used. If you need this feature you should build it yourself with use-move hook.

Accessibility

Slider and RangeSlider components are accessible by default:

  • Slider thumbs are focusable
  • When the user uses mouse to interact with a slider, focus is moved on slider track, when the user presses arrows focus is moved on thumb
  • Value can be changed with arrows with step increment/decrement

To label component for screen readers, add labels to thumbs:

<Slider thumbLabel="Thumb aria-label" />
<RangeSlider thumbFromLabel="First thumb aria-label" thumbToLabel="Second thumb aria-label" />

Keyboard interactions

KeyDescription
ArrowRight/ArrowUpIncreases slider value by one step
ArrowLeft/ArrowDownDecreases slider value by one step
HomeSets slider value to min value
EndSets slider value to max value

Slider component props

NameTypeDescription
color
MantineColor
Color from theme.colors
defaultValue
number
Default value for uncontrolled slider
disabled
boolean
Disables slider
inverted
boolean
Allows the track to be inverted
label
ReactNode | ((value: number) => ReactNode)
Function to generate label or any react node to render instead, set to null to disable label
labelAlwaysOn
boolean
If true label will be not be hidden when user stops dragging
labelTransition
MantineTransition
Label appear/disappear transition
labelTransitionDuration
number
Label appear/disappear transition duration in ms
labelTransitionTimingFunction
string
Label appear/disappear transition timing function, defaults to theme.transitionRimingFunction
marks
{ value: number; label?: ReactNode; }[]
Marks which will be placed on the track
max
number
Maximum possible value
min
number
Minimal possible value
name
string
Hidden input name, use with uncontrolled variant
onChange
(value: number) => void
Called each time value changes
onChangeEnd
(value: number) => void
Called when user stops dragging slider or changes value with arrows
precision
number
Amount of digits after the decimal point
radius
number | "xs" | "sm" | "md" | "lg" | "xl"
Key of theme.radius or any valid CSS value to set border-radius, "xl" by default
scale
(value: number) => number
A transformation function, to change the scale of the slider
showLabelOnHover
boolean
If true slider label will appear on hover
size
number | "xs" | "sm" | "md" | "lg" | "xl"
Controls size of track and thumb
step
number
Number by which value will be incremented/decremented with thumb drag and arrows
thumbChildren
ReactNode
Thumb children, can be used to add icon
thumbLabel
string
Thumb aria-label
thumbSize
number
Thumb width and height
value
number
Current value for controlled slider

RangeSlider component props

NameTypeDescription
color
MantineColor
Color from theme.colors
defaultValue
Value
Default value for uncontrolled slider
disabled
boolean
Disables slider
inverted
boolean
Allows the track to be inverted
label
ReactNode | ((value: number) => ReactNode)
Function to generate label or any react node to render instead, set to null to disable label
labelAlwaysOn
boolean
If true label will be not be hidden when user stops dragging
labelTransition
MantineTransition
Label appear/disappear transition
labelTransitionDuration
number
Label appear/disappear transition duration in ms
labelTransitionTimingFunction
string
Label appear/disappear transition timing function, defaults to theme.transitionRimingFunction
marks
{ value: number; label?: ReactNode; }[]
Marks which will be placed on the track
max
number
Maximum possible value
maxRange
number
Maximum range interval
min
number
Minimal possible value
minRange
number
Minimal range interval
name
string
Hidden input name, use with uncontrolled variant
onChange
(value: Value) => void
Called each time value changes
onChangeEnd
(value: Value) => void
Called when user stops dragging slider or changes value with arrows
precision
number
Amount of digits after the decimal point
radius
number | "xs" | "sm" | "md" | "lg" | "xl"
Key of theme.radius or any valid CSS value to set border-radius, theme.defaultRadius by default
scale
(value: number) => number
A transformation function, to change the scale of the slider
showLabelOnHover
boolean
If true slider label will appear on hover
size
number | "xs" | "sm" | "md" | "lg" | "xl"
Predefined track and thumb size, number to set sizes
step
number
Number by which value will be incremented/decremented with thumb drag and arrows
thumbChildren
ReactNode
Thumbs children, can be used to add icons
thumbFromLabel
string
First thumb aria-label
thumbSize
number
Thumb width and height
thumbToLabel
string
Second thumb aria-label
value
Value
Current value for controlled slider

Slider component Styles API

NameStatic selectorDescription
root.mantine-Slider-rootRoot element
trackContainer.mantine-Slider-trackContainerWrapper around track, handles drag events
track.mantine-Slider-trackTrack element, contains all other elements
bar.mantine-Slider-barFilled part of the track
thumb.mantine-Slider-thumbMain control
dragging.mantine-Slider-draggingStyles added to thumb while dragging
label.mantine-Slider-labelLabel element, displayed above thumb
marksContainer.mantine-Slider-marksContainerWrapper around all marks, helps position the marks above the track
markWrapper.mantine-Slider-markWrapperWrapper around mark, contains mark and mark label
mark.mantine-Slider-markMark displayed on the track
markFilled.mantine-Slider-markFilledStyles added to mark when it is located in filled area
markLabel.mantine-Slider-markLabelMark label, displayed below track

RangeSlider component Styles API

NameStatic selectorDescription
root.mantine-RangeSlider-rootRoot element
trackContainer.mantine-RangeSlider-trackContainerWrapper around track, handles drag events
track.mantine-RangeSlider-trackTrack element, contains all other elements
bar.mantine-RangeSlider-barFilled part of the track
thumb.mantine-RangeSlider-thumbMain control
dragging.mantine-RangeSlider-draggingStyles added to thumb while dragging
label.mantine-RangeSlider-labelLabel element, displayed above thumb
marksContainer.mantine-RangeSlider-marksContainerWrapper around all marks, helps position the marks above the track
markWrapper.mantine-RangeSlider-markWrapperWrapper around mark, contains mark and mark label
mark.mantine-RangeSlider-markMark displayed on the track
markFilled.mantine-RangeSlider-markFilledStyles added to mark when it is located in filled area
markLabel.mantine-RangeSlider-markLabelMark label, displayed below track