Skip to content

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

Free

Carousel with Thumbnails for Vue

Five numbered slides and a row of buttons 1 through 5 under them. The current button is filled, and there are no arrow buttons.

UI library: Ark UI

A wide frame shows one number, from 1 through 5. Under it, five buttons read 1 through 5. The button for the current slide is filled, and the others are outlines.

Use numbered buttons when people should jump to a slide. A Tabs row fits if each slide needs a name instead of a number. On Vue, Ark UI does not mark the current button.

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

Carousel anatomy: content, item, previous, next, indicator group

Usage

<div class="mx-auto flex w-full max-w-md flex-col gap-4">
  <Carousel @page-change="handlePageChange" :page="page" :slideCount="slides.length">
    <CarouselContent>
      <CarouselItem v-for="(slide, index) in slides" :index="index" :key="slide">
        <div class="flex aspect-2/1 items-center justify-center rounded-md border bg-background">
          <span class="font-semibold text-4xl">{{ slide }}</span>
        </div>
      </CarouselItem>
    </CarouselContent>
  </Carousel>
  <div class="flex justify-center gap-2">
    <Button
      v-for="(slide, index) in slides"
      :aria-current='page === index ? "true" : undefined'
      :aria-label="`Go to slide ${slide}`"
      :data-index="index"
      :key="slide"
      @click="handleThumbnailClick"
      :variant='page === index ? "default" : "outline"'
    >
      {{ slide }}
    </Button>
  </div>
</div>

FAQ

How do the buttons stay in sync with the slides?

The carousel is controlled: page is state, @page-change stores the new page, and each button sets page to its index.

What does each slide show?

Five slides. Each is an aspect-2/1 box with rounded-md border bg-background and the slide number in font-semibold text-4xl. The carousel and the buttons stack in a max-w-md column with gap-4.

How are the buttons styled?

A flex justify-center gap-2 row of Buttons, one per slide. The current one is variant="default", the others variant="outline". Change those, or the size, to restyle them.

Can I show pictures instead of numbers?

Yes. Put a small img in each button, with a fixed size such as size-12 and object-cover, and keep the aria-label so each button still has a name.

What if there are too many buttons for the row?

Make the row scroll: overflow-x-auto instead of justify-center. For more than ten or so slides, a page counter (Slide 3 of 24) is easier to use than a long row of buttons.

What will a screen reader say?

Each button's aria-label reads Go to slide 1 through Go to slide 5, and the current one has aria-current, so it's announced as current. Previous and next are left out here: the buttons replace them.

API Reference

Sets page-change="handlePageChange", page="page", slideCount="slides.length", v-for="(slide, index) in slides", index="index" and key="slide". The rest is on the Carousel page.

Button

Sets v-for="(slide, index) in slides", aria-current="page === index ? true : undefined", aria-label="`Go to slide ${slide}`", data-index="index", key="slide" and click="handleThumbnailClick". The rest is on the Button page.