Skip to content

shadcn.io is an independent project built on shadcn/ui

Free

Carousel Controls Button Group for Solid

Carousel controls for five slides: previous, next, and dots, plus a row that reads the slide as 1 / 5.

UI library: Ark UI

Controls for five slides, starting on slide 1, where Previous is disabled. Next stops on slide 5. The dots jump to a slide. The second row says Prev, shows the slide as 1 / 5, and Next. That middle readout does nothing.

Use the dots when there are only a few slides. The slides themselves belong in a Carousel. In Solid, Ark UI does not loop from the last slide back to the first.

Preview

Preview width

Installation

MCP · Pro
Make your AI a shadcn expert
Your agent installs components, builds pages and restyles your app from one prompt, in Claude Code, Cursor or VS Code.
Part of Pro

Anatomy

Button Group anatomy: root, group, button, separator

Usage

<div class="flex flex-col gap-4">
      <ButtonGroup aria-label="Slides">
        <Button aria-label="Previous slide" disabled={slide() === 1} onClick={goToPrevious} size="icon-sm" variant="outline">
          <ChevronLeftIcon aria-hidden="true" />
        </Button>
        {SLIDES.map(item => <Button aria-current={slide() === item ? "true" : undefined} aria-label={`Slide ${item}`} onClick={goToSlide} pill size="icon-sm" value={String(item)} variant={slide() === item ? "default" : "outline"} />)}
        <Button aria-label="Next slide" disabled={slide() === TOTAL_SLIDES} onClick={goToNext} size="icon-sm" variant="outline">
          <ChevronRightIcon aria-hidden="true" />
        </Button>
      </ButtonGroup>
      <ButtonGroup aria-label="Slides">
        <Button disabled={slide() === 1} onClick={goToPrevious} size="sm" variant="outline">
          <ChevronLeftIcon aria-hidden="true" data-icon="inline-start" />
          Prev
        </Button>
        <Button size="sm" variant="outline">
          {slide()} / {TOTAL_SLIDES}
        </Button>
        <Button disabled={slide() === TOTAL_SLIDES} onClick={goToNext} size="sm" variant="outline">
          Next
          <ChevronRightIcon aria-hidden="true" data-icon="inline-end" />
        </Button>
      </ButtonGroup>
    </div>

FAQ

How is the slide tracked?

A number from 1 to 5, starting at 1. Previous and next step by one, and each dot carries its slide number as its value, so pressing it jumps there.

When are previous and next disabled?

Previous on slide 1 and next on slide 5, in both rows. They get disabled from those checks.

How are the dots named?

Each dot has an aria-label, Slide 1 to Slide 5, and the current one sets aria-current. The dots are pill icon buttons with no content.

Does the 1 / 5 button do anything?

No. It shows the position and has no handler. Use ButtonGroupText if it shouldn't take focus.

Where are the slides?

The demo has none; it only keeps the number. The Carousel component has its own previous, next and indicator parts if you want a complete one.

How do I make it loop?

Wrap the number instead of clamping it: next on slide 5 goes to 1, and previous on 1 goes to 5. Then remove the disabled checks.

API Reference

Button Group

Sets aria-label="Slides". The rest is on the Button Group page.

Button

Sets aria-label="Previous slide", disabled={slide() === 1}, onClick={goToPrevious}, size="icon-sm", variant="outline" and aria-current={slide() === item ? "true" : undefined}. The rest is on the Button page.