shadcn.io is an independent project built on shadcn/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 React, Base UI does not loop from the last slide back to the first.
Installation
Anatomy

Usage
<div className="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}`}
key={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" />
{/* The rest of the file is under Installation. */}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.
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.





