New Compose Multiplatform components arrived on Composables UICheck it out →


A horizontal indicator for a Pager, representing the currently active page and total pages drawn using a [Shape]. It shows up to 6 pages on the screen and doesn't represent the exact page index if there are more than 6 pages. Instead of showing the exact position, [HorizontalPageIndicator] shows a half-size indicator on the left or on the right if there are more pages.

Here's how different positions 0..10 might be visually represented: "X" is selected item, "O" and "o" full and half size items respectively.

O X O O O o - 2nd position out of 10. There are no more items on the left but more on the right o O O O X o - might be 6, 7 or 8 out of 10, as there are more possible items on the left and on the right o O O O X O - is 9 out of 10, as there're no more items on the right

[HorizontalPageIndicator] may be linear or curved, depending on [indicatorStyle]. By default it depends on the screen shape of the device - for circular screens it will be curved, whilst for square screens it will be linear.

This component also allows customising the [indicatorShape], which defines how the indicator is visually represented.

Last updated:


dependencies {


fun HorizontalPageIndicator(
    pageIndicatorState: PageIndicatorState,
    modifier: Modifier = Modifier,
    indicatorStyle: PageIndicatorStyle =,
    selectedColor: Color = MaterialTheme.colors.onBackground,
    unselectedColor: Color = selectedColor.copy(alpha = 0.3f),
    indicatorSize: Dp = 6.dp,
    spacing: Dp = 4.dp,
    indicatorShape: Shape = CircleShape


pageIndicatorStateThe state object of a [HorizontalPageIndicator] to be used to observe the Pager's state.
modifierModifier to be applied to the [HorizontalPageIndicator]
indicatorStyleThe style of [HorizontalPageIndicator] - may be linear or curved. By default determined by the screen shape.
selectedColorThe color of the selected [HorizontalPageIndicator] item
unselectedColorThe color of unselected [HorizontalPageIndicator] items. Defaults to [selectedColor] with 30% alpha
indicatorSizeThe size of each [HorizontalPageIndicator] item in [Dp]
spacingThe spacing between indicator items in [Dp]
indicatorShapeThe shape of each [HorizontalPageIndicator] item. Defaults to [CircleShape]

Code Example


fun HorizontalPageIndicatorSample() {
    val maxPages = 9
    var selectedPage by remember { mutableStateOf(0) }
    var finalValue by remember { mutableStateOf(0) }

    val animatedSelectedPage by animateFloatAsState(
        targetValue = selectedPage.toFloat(),
    ) {
        finalValue = it.toInt()

    val pageIndicatorState: PageIndicatorState = remember {
        object : PageIndicatorState {
            override val pageOffset: Float
                get() = animatedSelectedPage - finalValue
            override val selectedPage: Int
                get() = finalValue
            override val pageCount: Int
                get() = maxPages

    Box(modifier = Modifier.fillMaxSize().padding(6.dp)) {
            modifier = Modifier.align(Alignment.Center),
            value = selectedPage,
            increaseIcon = { Icon(InlineSliderDefaults.Increase, "Increase") },
            decreaseIcon = { Icon(InlineSliderDefaults.Decrease, "Decrease") },
            valueProgression = 0 until maxPages,
            onValueChange = { selectedPage = it }
            pageIndicatorState = pageIndicatorState