---
title: Slider
description: A slider component with custom track and thumb slots.
---



```kotlin expandable title="SliderDemo.kt" githubUrl="https://github.com/composablehorizons/compose-unstyled/blob/main/demo/src/commonMain/kotlin/com/composeunstyled/demo/slider/SliderDemo.kt"
import androidx.compose.animation.animateColorAsState
import androidx.compose.animation.core.animateDpAsState
import androidx.compose.foundation.background
import androidx.compose.foundation.hoverable
import androidx.compose.foundation.interaction.MutableInteractionSource
import androidx.compose.foundation.interaction.collectIsFocusedAsState
import androidx.compose.foundation.interaction.collectIsHoveredAsState
import androidx.compose.foundation.interaction.collectIsPressedAsState
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.fillMaxHeight
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.layout.widthIn
import androidx.compose.foundation.shape.CircleShape
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableFloatStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import com.composeunstyled.UnstyledSlider
import com.composeunstyled.demo.borderToken
import com.composeunstyled.demo.colors
import com.composeunstyled.demo.contentToken
import com.composeunstyled.theme.Theme

@Preview
@Composable
fun SliderDemo() {
  val pillShape = RoundedCornerShape(100)
  Box(
    modifier = Modifier.fillMaxSize(),
    contentAlignment = Alignment.Center,
  ) {
    val interactionSource = remember { MutableInteractionSource() }
    val isFocused by interactionSource.collectIsFocusedAsState()
    val isPressed by interactionSource.collectIsPressedAsState()

    var value by remember { mutableFloatStateOf(0.7f) }

    Box(
      modifier = Modifier
        .padding(horizontal = 16.dp)
        .widthIn(max = 480.dp)
        .fillMaxWidth(),
    ) {
      UnstyledSlider(
        interactionSource = interactionSource,
        value = value,
        onValueChange = { value = it },
        modifier = Modifier.fillMaxWidth(),
        track = { state ->
          Box(
            Modifier
              .fillMaxWidth()
              .height(8.dp)
              .padding(horizontal = 16.dp)
              .clip(pillShape),
          ) {
            // the 'not yet completed' part of the track
            Box(
              Modifier
                .fillMaxHeight()
                .fillMaxWidth()
                .background(Theme[colors][borderToken]),
            )
            // the 'completed' part of the track
            Box(
              Modifier
                .fillMaxHeight()
                .fillMaxWidth(state.fraction)
                .background(Theme[colors][contentToken]),
            )
          }
        },
        thumb = {
          val thumbSize by animateDpAsState(targetValue = if (isPressed) 22.dp else 18.dp)

          val thumbInteractionSource = remember { MutableInteractionSource() }
          val isHovered by thumbInteractionSource.collectIsHoveredAsState()
          val glowColor by animateColorAsState(
            if (isFocused || isHovered) {
              Theme[colors][contentToken].copy(0.16f)
            } else {
              Color.Transparent
            },
          )
          // keep the size fixed to ensure that the resizing animation is always centered
          Box(
            modifier = Modifier.size(36.dp).clip(CircleShape).background(glowColor),
            contentAlignment = Alignment.Center,
          ) {
            Box(
              modifier = Modifier
                .size(thumbSize)
                .hoverable(thumbInteractionSource)
                .clip(CircleShape)
                .background(Theme[colors][contentToken]),
            )
          }
        },
      )
    }
  }
}
```



## Features

- Horizontal and vertical sliders
- Discrete step support
- Custom track and thumb slots
- Keyboard and screen reader value changes

## Installation

```kotlin
implementation("com.composables:composeunstyled-slider:2.10.0")
```

## Anatomy

```kotlin
UnstyledSlider(
  value = value,
  onValueChange = onValueChange,
  track = {
  },
  thumb = {
  },
)
```

## Concepts

- `UnstyledSlider` represents the interactive range users can drag or adjust.
- `SliderState` is passed to the track and thumb slots.
- The `track` slot renders below the thumb.
- The `thumb` slot renders at the current slider offset.

## Accessibility

`UnstyledSlider` exposes progress semantics and supports arrow keys, Page Up, Page Down, Home, and End.

## Code Examples

### Creating a stepped slider

Use the `steps` parameter to snap the slider value to discrete stops:

```kotlin expandable
UnstyledSlider(
  value = value,
  onValueChange = { value = it },
  steps = 4,
  track = { state ->
    BasicText("${state.value}")
  },
  thumb = { state ->
    BasicText("${state.value}")
  },
)
```

### Using a custom value range

Use the `valueRange` parameter when the slider value is not from `0f` to `1f`:

```kotlin expandable
UnstyledSlider(
  value = volume,
  onValueChange = { volume = it },
  valueRange = 0f..100f,
  track = { state ->
    BasicText("${state.value}")
  },
  thumb = { state ->
    BasicText("${state.value}")
  },
)
```

### Creating a vertical slider

Use the `orientation` parameter to make the slider vertical:

```kotlin expandable
UnstyledSlider(
  value = value,
  onValueChange = { value = it },
  orientation = Orientation.Vertical,
  track = { state ->
    BasicText("${state.value}")
  },
  thumb = { state ->
    BasicText("${state.value}")
  },
)
```

### Running code after value changes finish

Use the `onValueChangeFinished` callback to react after drag, tap, keyboard, or screen reader changes finish:

```kotlin expandable
UnstyledSlider(
  value = value,
  onValueChange = { value = it },
  onValueChangeFinished = { save(value) },
  track = { state ->
    BasicText("${state.value}")
  },
  thumb = { state ->
    BasicText("${state.value}")
  },
)
```

## API Reference

### SliderState

| Parameter | Type | Description |
|-----------|------|-------------|
| `valueRange` | `ClosedFloatingPointRange<Float>` | The range of values the slider can take. |
| `steps` | `Int` | The number of discrete steps in the slider. |
| `enabled` | `Boolean` | Whether the slider can receive user input. |
| `orientation` | `Orientation` | Horizontal or vertical slider orientation. |
| `isRtl` | `Boolean` |  |
| `isDragging` | `Boolean` |  |
| `isPressed` | `Boolean` |  |
| `isFocused` | `Boolean` |  |
| `tickFractions` | `FloatArray` |  |
| `value` | `Float` | The current value of the slider. |
| `fraction` | `Float` |  |
### UnstyledSlider

| Parameter | Type | Description |
|-----------|------|-------------|
| `value` | `Float` |  |
| `onValueChange` | `(Float) -> Unit` | Callback invoked when the user changes the value. |
| `modifier` | `Modifier` | Modifier to be applied to the slider. |
| `enabled` | `Boolean` | Whether the slider can receive user input. |
| `interactionSource` | `MutableInteractionSource?` | Interaction source for press, focus, and drag interactions. |
| `valueRange` | `ClosedFloatingPointRange<Float>` |  |
| `steps` | `Int` |  |
| `onValueChangeFinished` | `(() -> Unit)?` |  |
| `orientation` | `Orientation` | Horizontal or vertical slider orientation. |
| `reverseDirection` | `Boolean` | Whether to reverse the visual and input direction. |
| `track` | `(SliderState) -> Unit` | Composable function to define the track of the slider. |
| `thumb` | `(SliderState) -> Unit` | Composable function to define the thumb of the slider. |
