Slider
Common
Component in Material 3 Compose
Sliders allow users to make selections from a range of values.
It uses [SliderDefaults.Thumb] and [SliderDefaults.Track] as the thumb and track.
Sliders reflect a range of values along a horizontal bar, from which users may select a single value. They are ideal for adjusting settings such as volume, brightness, or applying image filters.

Last updated:
Installation
dependencies {
implementation("androidx.compose.material3:material3:1.4.0-alpha07")
}
Overloads
@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun Slider(
value: Float,
onValueChange: (Float) -> Unit,
modifier: Modifier = Modifier,
enabled: Boolean = true,
valueRange: ClosedFloatingPointRange<Float> = 0f..1f,
@IntRange(from = 0) steps: Int = 0,
onValueChangeFinished: (() -> Unit)? = null,
colors: SliderColors = SliderDefaults.colors(),
interactionSource: MutableInteractionSource = remember { MutableInteractionSource() }
)
Parameters
name | description |
---|---|
value | current value of the slider. If outside of [valueRange] provided, value will be coerced to this range. |
onValueChange | callback in which value should be updated |
modifier | the [Modifier] to be applied to this slider |
enabled | controls the enabled state of this slider. When false , this component will not respond to user input, and it will appear visually disabled and disabled to accessibility services. |
valueRange | range of values that this slider can take. The passed [value] will be coerced to this range. |
steps | if positive, specifies the amount of discrete allowable values between the endpoints of [valueRange]. For example, a range from 0 to 10 with 4 [steps] allows 4 values evenly distributed between 0 and 10 (i.e., 2, 4, 6, 8). If [steps] is 0, the slider will behave continuously and allow any value from the range. Must not be negative. |
onValueChangeFinished | called when value change has ended. This should not be used to update the slider value (use [onValueChange] instead), but rather to know when the user has completed selecting a new value by ending a drag or a click. |
colors | [SliderColors] that will be used to resolve the colors used for this slider in different states. See [SliderDefaults.colors]. |
interactionSource | the [MutableInteractionSource] representing the stream of [Interaction]s for this slider. You can create and pass in your own remember ed instance to observe [Interaction]s and customize the appearance / behavior of this slider in different states. |
@Composable
@ExperimentalMaterial3Api
fun Slider(
value: Float,
onValueChange: (Float) -> Unit,
modifier: Modifier = Modifier,
enabled: Boolean = true,
onValueChangeFinished: (() -> Unit)? = null,
colors: SliderColors = SliderDefaults.colors(),
interactionSource: MutableInteractionSource = remember { MutableInteractionSource() },
@IntRange(from = 0) steps: Int = 0,
thumb: @Composable (SliderState) -> Unit = {
SliderDefaults.Thumb(
interactionSource = interactionSource,
colors = colors,
enabled = enabled
)
},
track: @Composable (SliderState) -> Unit = { sliderState ->
SliderDefaults.Track(colors = colors, enabled = enabled, sliderState = sliderState)
},
valueRange: ClosedFloatingPointRange<Float> = 0f..1f
)
Parameters
name | description |
---|---|
value | current value of the slider. If outside of [valueRange] provided, value will be coerced to this range. |
onValueChange | callback in which value should be updated |
modifier | the [Modifier] to be applied to this slider |
enabled | controls the enabled state of this slider. When false , this component will not respond to user input, and it will appear visually disabled and disabled to accessibility services. |
onValueChangeFinished | called when value change has ended. This should not be used to update the slider value (use [onValueChange] instead), but rather to know when the user has completed selecting a new value by ending a drag or a click. |
colors | [SliderColors] that will be used to resolve the colors used for this slider in different states. See [SliderDefaults.colors]. |
interactionSource | the [MutableInteractionSource] representing the stream of [Interaction]s for this slider. You can create and pass in your own remember ed instance to observe [Interaction]s and customize the appearance / behavior of this slider in different states. |
steps | if positive, specifies the amount of discrete allowable values between the endpoints of [valueRange]. For example, a range from 0 to 10 with 4 [steps] allows 4 values evenly distributed between 0 and 10 (i.e., 2, 4, 6, 8). If [steps] is 0, the slider will behave continuously and allow any value from the range. Must not be negative. |
thumb | the thumb to be displayed on the slider, it is placed on top of the track. The lambda receives a [SliderState] which is used to obtain the current active track. |
track | the track to be displayed on the slider, it is placed underneath the thumb. The lambda receives a [SliderState] which is used to obtain the current active track. |
valueRange | range of values that this slider can take. The passed [value] will be coerced to this range. |
@Composable
@ExperimentalMaterial3Api
fun Slider(
state: SliderState,
modifier: Modifier = Modifier,
enabled: Boolean = true,
colors: SliderColors = SliderDefaults.colors(),
interactionSource: MutableInteractionSource = remember { MutableInteractionSource() },
thumb: @Composable (SliderState) -> Unit = {
SliderDefaults.Thumb(
interactionSource = interactionSource,
colors = colors,
enabled = enabled
)
},
track: @Composable (SliderState) -> Unit = { sliderState ->
SliderDefaults.Track(colors = colors, enabled = enabled, sliderState = sliderState)
}
)
Parameters
name | description |
---|---|
state | [SliderState] which contains the slider's current value. |
modifier | the [Modifier] to be applied to this slider |
enabled | controls the enabled state of this slider. When false , this component will not respond to user input, and it will appear visually disabled and disabled to accessibility services. |
colors | [SliderColors] that will be used to resolve the colors used for this slider in different states. See [SliderDefaults.colors]. |
interactionSource | the [MutableInteractionSource] representing the stream of [Interaction]s for this slider. You can create and pass in your own remember ed instance to observe [Interaction]s and customize the appearance / behavior of this slider in different states. |
thumb | the thumb to be displayed on the slider, it is placed on top of the track. The lambda receives a [SliderState] which is used to obtain the current active track. |
track | the track to be displayed on the slider, it is placed underneath the thumb. The lambda receives a [SliderState] which is used to obtain the current active track. |
Code Examples
SliderSample
@Preview
@Composable
fun SliderSample() {
var sliderPosition by remember { mutableStateOf(0f) }
Column(modifier = Modifier.padding(horizontal = 16.dp)) {
Text(text = "%.2f".format(sliderPosition))
Slider(
modifier = Modifier.semantics { contentDescription = "Localized Description" },
value = sliderPosition,
onValueChange = { sliderPosition = it }
)
}
}
StepsSliderSample
@Preview
@Composable
fun StepsSliderSample() {
var sliderPosition by remember { mutableStateOf(0f) }
Column(modifier = Modifier.padding(horizontal = 16.dp)) {
Text(text = sliderPosition.roundToInt().toString())
Slider(
modifier = Modifier.semantics { contentDescription = "Localized Description" },
value = sliderPosition,
onValueChange = { sliderPosition = it },
valueRange = 0f..100f,
onValueChangeFinished = {
// launch some business logic update with the state you hold
// viewModel.updateSelectedSliderValue(sliderPosition)
},
// Only allow multiples of 10. Excluding the endpoints of `valueRange`,
// there are 9 steps (10, 20, ..., 90).
steps = 9
)
}
}
SliderWithCustomThumbSample
@OptIn(ExperimentalMaterial3Api::class)
@Preview
@Composable
fun SliderWithCustomThumbSample() {
var sliderPosition by remember { mutableStateOf(0f) }
val interactionSource: MutableInteractionSource = remember { MutableInteractionSource() }
Column(modifier = Modifier.padding(horizontal = 16.dp)) {
Slider(
modifier = Modifier.semantics { contentDescription = "Localized Description" },
value = sliderPosition,
onValueChange = { sliderPosition = it },
valueRange = 0f..100f,
interactionSource = interactionSource,
onValueChangeFinished = {
// launch some business logic update with the state you hold
// viewModel.updateSelectedSliderValue(sliderPosition)
},
thumb = {
Label(
label = {
PlainTooltip(modifier = Modifier.sizeIn(45.dp, 25.dp).wrapContentWidth()) {
Text("%.2f".format(sliderPosition))
}
},
interactionSource = interactionSource
) {
Icon(
imageVector = Icons.Filled.Favorite,
contentDescription = null,
modifier = Modifier.size(ButtonDefaults.IconSize),
tint = Color.Red
)
}
}
)
}
}
SliderWithCustomTrackAndThumbSample
@OptIn(ExperimentalMaterial3Api::class)
@Preview
@Composable
fun SliderWithCustomTrackAndThumbSample() {
val sliderState = remember {
SliderState(
valueRange = 0f..100f,
onValueChangeFinished = {
// launch some business logic update with the state you hold
// viewModel.updateSelectedSliderValue(sliderPosition)
}
)
}
val interactionSource = remember { MutableInteractionSource() }
val colors = SliderDefaults.colors(thumbColor = Color.Red, activeTrackColor = Color.Red)
Column(modifier = Modifier.padding(horizontal = 16.dp)) {
Text(text = "%.2f".format(sliderState.value))
Slider(
state = sliderState,
modifier = Modifier.semantics { contentDescription = "Localized Description" },
interactionSource = interactionSource,
thumb = {
SliderDefaults.Thumb(interactionSource = interactionSource, colors = colors)
},
track = { SliderDefaults.Track(colors = colors, sliderState = sliderState) }
)
}
}
SliderWithTrackIconsSample
@OptIn(ExperimentalMaterial3Api::class, ExperimentalMaterial3ExpressiveApi::class)
@Preview
@Composable
fun SliderWithTrackIconsSample() {
val sliderState = remember {
SliderState(
valueRange = 0f..100f,
onValueChangeFinished = {
// launch some business logic update with the state you hold
// viewModel.updateSelectedSliderValue(sliderPosition)
}
)
}
val interactionSource = remember { MutableInteractionSource() }
val startIcon = rememberVectorPainter(Icons.Filled.MusicNote)
val endIcon = rememberVectorPainter(Icons.Filled.MusicOff)
Column(modifier = Modifier.padding(horizontal = 16.dp)) {
Text(text = "%.2f".format(sliderState.value))
Slider(
state = sliderState,
modifier = Modifier.semantics { contentDescription = "Localized Description" },
interactionSource = interactionSource,
track = {
val iconSize = DpSize(20.dp, 20.dp)
val iconPadding = 10.dp
val thumbTrackGapSize = 6.dp
val activeIconColor = SliderDefaults.colors().activeTickColor
val inactiveIconColor = SliderDefaults.colors().inactiveTickColor
val trackIconStart: DrawScope.(Offset, Color) -> Unit = { offset, color ->
translate(offset.x + iconPadding.toPx(), offset.y) {
with(startIcon) {
draw(iconSize.toSize(), colorFilter = ColorFilter.tint(color))
}
}
}
val trackIconEnd: DrawScope.(Offset, Color) -> Unit = { offset, color ->
translate(offset.x - iconPadding.toPx() - iconSize.toSize().width, offset.y) {
with(endIcon) {
draw(iconSize.toSize(), colorFilter = ColorFilter.tint(color))
}
}
}
SliderDefaults.Track(
sliderState = sliderState,
modifier =
Modifier.height(36.dp).drawWithContent {
drawContent()
val yOffset = size.height / 2 - iconSize.toSize().height / 2
val activeTrackStart = 0f
val activeTrackEnd =
size.width * sliderState.coercedValueAsFraction -
thumbTrackGapSize.toPx()
val inactiveTrackStart = activeTrackEnd + thumbTrackGapSize.toPx() * 2
val inactiveTrackEnd = size.width
val activeTrackWidth = activeTrackEnd - activeTrackStart
val inactiveTrackWidth = inactiveTrackEnd - inactiveTrackStart
if (
iconSize.toSize().width < activeTrackWidth - iconPadding.toPx() * 2
) {
trackIconStart(Offset(activeTrackStart, yOffset), activeIconColor)
trackIconEnd(Offset(activeTrackEnd, yOffset), activeIconColor)
}
if (
iconSize.toSize().width <
inactiveTrackWidth - iconPadding.toPx() * 2
) {
trackIconStart(
Offset(inactiveTrackStart, yOffset),
inactiveIconColor
)
trackIconEnd(Offset(inactiveTrackEnd, yOffset), inactiveIconColor)
}
},
trackCornerSize = 12.dp,
drawStopIndicator = null,
thumbTrackGapSize = thumbTrackGapSize
)
}
)
}
}