MiHCM
layout/@mihcm/ui·v0.21.0·stable

Carousel

Composable carousel powered by Embla. Supports horizontal/vertical orientation, loop, and prev/next controls.

Carousel

A slideshow component for cycling through a series of content panels with previous/next controls.

When to use

  • Image galleries displaying a collection of photos or media.
  • Product showcases highlighting multiple items in limited space.
  • Testimonial sliders rotating customer quotes.
  • Onboarding flows stepping through feature introductions.

When NOT to use

  • For content that must be visible at all times — use a grid or list.
  • For critical navigation — users may miss items they never scroll to.
  • For single-item display — use a card or hero section.

Import

import {
  Carousel,
  CarouselContent,
  CarouselItem,
  CarouselPrevious,
  CarouselNext,
} from '@mihcm/ui/Carousel';

Basic usage

<Carousel>
  <CarouselContent>
    <CarouselItem>Slide 1</CarouselItem>
    <CarouselItem>Slide 2</CarouselItem>
    <CarouselItem>Slide 3</CarouselItem>
  </CarouselContent>
  <CarouselPrevious />
  <CarouselNext />
</Carousel>

Vertical orientation

Pass orientation="vertical" to scroll vertically. Constrain the height on CarouselContent.

<Carousel orientation="vertical">
  <CarouselContent className="h-[200px]">
    <CarouselItem>…</CarouselItem>
  </CarouselContent>
  <CarouselPrevious />
  <CarouselNext />
</Carousel>

Multiple items per view

Control how many items are visible by setting a basis-* class on each CarouselItem.

<CarouselItem className="basis-1/3">…</CarouselItem>

Use responsive basis classes for production layouts:

<CarouselItem className="basis-full sm:basis-1/2 lg:basis-1/3">…</CarouselItem>

For a carousel like the Porsche configurator reference, combine these pieces:

  • Use a visible heading and a short description outside the scroll track.
  • Use opts={{ align: 'start', loop: true }} when the carousel should rewind.
  • Use responsive basis-* classes to control visible slide count per breakpoint.
  • Add container padding around the carousel to reveal part of the next or previous slide.
  • Use useCarousel() to build pagination dots or progress indicators.
  • Keep pagination buttons real <button> elements with aria-label and aria-current.
<section aria-labelledby="workflow-carousel-heading">
  <h2 id="workflow-carousel-heading">Related workflows</h2>
  <Carousel opts={{ align: 'start', loop: true }} aria-label="Related workflows">
    <CarouselContent>
      {workflows.map((workflow) => (
        <CarouselItem key={workflow.title} className="basis-full sm:basis-1/2 lg:basis-1/3">
          <WorkflowCard {...workflow} />
        </CarouselItem>
      ))}
    </CarouselContent>
    <CarouselPrevious />
    <CarouselNext />
    <CarouselPagination />
  </Carousel>
</section>

Composition

  • Wrap slides in CarouselContent, each in a CarouselItem. Place CarouselPrevious / CarouselNext outside the content.
  • Use basis-1/N on CarouselItem to show multiple items per view.
  • Pass opts={{ loop: true }} to enable infinite cycling. Without it, buttons disable at the edges.
  • Pass opts={{ align: 'start' }} for card rails and opts={{ align: 'center' }} for hero-like galleries.
  • Use useCarousel() for pagination, counters, selected slide state, and custom controls.
  • orientation="vertical" requires a constrained height on CarouselContent.
  • ScrollArea — free-scroll containers without prev/next controls.
  • Tabs — switching between distinct content panels.