Sliders pick a number from a range by feel rather than by typing — volume, brightness, a price filter. Flutter's Slider uses the same controlled pattern as checkboxes: a value in state and an onChanged that you update with setState. Its sibling RangeSlider adds a second thumb for a low-to-high range. This guide covers the basic slider, snapping with divisions and labels, the range slider with RangeValues, styling with SliderTheme, and the onChangeEnd trick for expensive work, with paste-ready code.

The Complete Flutter Guide: Build Android, iOS and Web apps
Go from scratch to building industry-standard apps with Riverpod, Firebase, animations, REST APIs, and more.
Enrol nowEvery snippet below is paste-ready against current stable Flutter. A slider shares its controlled pattern with the checkbox, radio, and switch widgets — value in, change out.
We'll build a basic slider, snap it to whole numbers, add a range slider, style it, and defer heavy work to onChangeEnd.
If you'd rather watch a filter panel with sliders built live, the channel covers these input patterns in real apps.
A basic slider
Slider takes a value (a double in state), a min and max, and an onChanged that updates the value. The thumb only moves because you call setState — the slider stores nothing itself.
double _volume = 40;
Slider(
value: _volume,
min: 0,
max: 100,
onChanged: (value) => setState(() => _volume = value),
)
Omit min and max and the range defaults to 0.0–1.0. Drag continuously like this and the slider reports fractional values, which is right for smooth controls like volume or opacity.
Snap to whole numbers
For discrete steps — a 1–5 rating, a count — set divisions to the number of equal steps. Add a label to float the current value above the thumb as the user drags.
Slider(
value: _rating,
min: 0,
max: 10,
divisions: 10, // snaps to whole numbers
label: _rating.round().toString(),
onChanged: (value) => setState(() => _rating = value),
)
With ten divisions across a 0–10 range the slider clicks to each integer. Without divisions it stays continuous, so reach for divisions whenever the value should be a clean step rather than a fraction.

Build interactive, filterable UIs
The Complete Flutter Guide covers sliders, filters, and full forms inside real, shipped apps.
Enrol nowA range slider
For a low-and-high bound — a price filter, an age range — use RangeSlider with a RangeValues holding a start and end. It shows two thumbs the user drags independently.
RangeValues _price = const RangeValues(20, 80);
RangeSlider(
values: _price,
min: 0,
max: 100,
divisions: 20,
labels: RangeLabels('${_price.start.round()}', '${_price.end.round()}'),
onChanged: (values) => setState(() => _price = values),
)
Read _price.start and _price.end for the chosen range — exactly what a "£20 to £80" product filter needs. The same divisions and labels options apply, now as a pair.
Styling with SliderTheme
Track colour, thumb shape, and tick marks come from SliderTheme. Wrap the slider in a SliderTheme with a SliderThemeData to override the active and inactive track colours, the thumb size, or the overlay. On Material 3 the defaults already follow your colour scheme, so you usually only adjust a colour or two rather than rebuild the whole look.
Defer heavy work with onChangeEnd
onChanged fires on every frame of the drag, which you need for a smooth thumb — but it's the wrong place for a network call or a database query. onChangeEnd fires once, when the drag finishes, so run expensive work there.
Slider(
value: _price,
min: 0,
max: 1000,
onChanged: (v) => setState(() => _price = v), // smooth UI
onChangeEnd: (v) => _fetchResultsForPrice(v), // once, on release
)
This keeps the slider responsive while firing the costly operation only when the user settles — a small split that avoids hammering an API on every pixel of movement.
Common mistakes
- Forgetting setState in onChanged. The thumb won't move; the slider is controlled.
- A value outside min–max. The value must stay within the range or it asserts.
- Expensive work in onChanged. It runs every frame; use
onChangeEndfor network or database calls. - No divisions for discrete values. Continuous sliders report fractions; add
divisionsto snap. - An int instead of a double. Slider values are doubles; round only when you read them.
Frequently asked questions
How do I add a slider in Flutter?
Use Slider with a value double, min, max, and an onChanged that updates the value with setState.
How do I make a Flutter Slider snap to whole numbers?
Set divisions to the number of steps between min and max, and add a label to show the current value.
How do I create a range slider in Flutter?
Use RangeSlider with a RangeValues of start and end; read values.start and values.end for the range.
What is the difference between onChanged and onChangeEnd on a Flutter Slider?
onChanged fires continuously while dragging; onChangeEnd fires once on release. Use the latter for expensive work like API calls.
Further reads
Keep going with the tutorials that pair with this guide:
- Flutter Development Guide 2026 — the full Flutter hub.
- Flutter Checkbox, Radio, and Switch — the other controlled selection widgets.
- Flutter DropdownButton — the select-menu input.
- Flutter Date and Time Pickers — another value-picking input.
- Flutter Material Widgets Catalogue — the full input family.
Sources: Flutter documentation — Slider, RangeSlider, RangeValues, RangeLabels, and SliderTheme / SliderThemeData API references (docs.flutter.dev). Verified against current stable Flutter.