KKUONIDesign System

Components

Carousel

Beta

Horizontally scrolling content slider with previous/next arrow buttons and dot indicators. Used for destination cards, hotel photos, and offer showcases.

Kenya

Purpose

The Carousel displays a horizontal sequence of cards or items when showing all of them simultaneously would require too much vertical space or visual density. It is used for:

  • Destination listing carousels — featured destinations on the homepage
  • Hotel gallery strips — multiple room or property photos
  • Offer rows — "Deals of the week" on the offers page
  • Related holidays — "You might also like" at the bottom of a detail page

The Carousel manages its own slide position state. Pass any content via renderItem — the Carousel handles the scroll track, arrows, and dot indicators. On the last slide group, the next arrow disables. On the first, the previous arrow disables.

Usage

Reach for Carousel when showing every item at once would take too much vertical space or visual density — a homepage destinations row, a hotel photo strip, or a "you might also like" module. When the content is purely a set of images meant to be viewed one at a time (e.g. a hotel's full photo set on its detail page), prefer ImageGallery, which is optimised for that single-purpose viewing pattern.

Carousels typically sit within a titled content section on a landing or detail page, scrolling horizontally within the page's normal vertical flow.

Anatomy

Maldives
  1. 1
    Slide trackHorizontal flex container. Clip overflow, translate-x to slide. Transition 300ms ease-out.
  2. 2
    Slide itemEach item wrapped in a role="group" div with aria-roledescription="slide" and aria-label="Slide N of M".
  3. 3
    Previous buttonCircular outline button with ChevronLeft. Disabled on first slide.
  4. 4
    Dot indicatorsPill-shaped dots — active dot is wider (w-6) in teal, inactive dots are circles (w-2) in grey.
  5. 5
    Next buttonCircular outline button with ChevronRight. Disabled on last slide group.

Variants

Multiple slides visible

Use slidesPerView to show more than one slide at a time.

Kenya
Maldives
Sri Lanka

Without dots

Use showDots={false} for compact carousels where arrows alone are sufficient navigation.

January
February
March
April

Without arrows

For touch-first carousels or when the scroll behaviour provides its own affordance.

Luxury Resorts

States

ElementStateAppearance
Previous buttonDefaultWhite bg, grey border
Previous buttonHoverTeal border, teal text
Previous buttonDisabled (first slide)40% opacity
Next buttonDefaultWhite bg, grey border
Next buttonDisabled (last group)40% opacity
DotInactivew-2 grey-300 circle
DotActivew-6 teal pill
ArrowsFocusTeal focus ring
DotsFocusTeal focus ring

Best practices

Do

Match slidesPerView to the number of cards that fit naturally at the target breakpoint.

slidesPerView={3} with gap={24} shows a grid-like layout for destination cards.

Don't

Always use slidesPerView=1 regardless of viewport width — adapt the value per breakpoint using CSS or a responsive wrapper.

slidesPerView={1} on a desktop-wide carousel wastes screen space and increases click count.

Do

Always pass ariaLabel to describe the carousel's content to assistive technology.

ariaLabel='Featured destinations' gives screen reader users context for the region.

Don't

Omit the ariaLabel prop.

An unlabelled carousel region gives screen readers no context for what is being displayed.

Do

Place properly structured card components inside renderItem — links, headings, and images should be complete within each slide.

Cards inside a Carousel should have their own heading, image, and link for accessibility.

Don't

Place non-interactive decorative images as the only content inside slides.

Icon-only slides leave screen reader users without content to interact with.

Props

PropTypeDefaultDescription
items*T[]Array of data items to render. Each item is passed to renderItem.
renderItem*(item: T, index: number) => ReactNodeRender function called for each item. Return a slide's content.
slidesPerViewnumber1Number of slides visible at once. Determines slide width as a fraction of the container.
gapnumber16Gap between slides in pixels.
showDotsbooleantrueWhether to show dot indicators below the carousel.
showArrowsbooleantrueWhether to show the previous/next arrow buttons.
ariaLabelstring'Carousel'Accessible label for the carousel region.
classNamestringAdditional Tailwind classes on the root container.

Accessibility

ARIA roles

<div role="region" aria-label="Featured destinations" aria-roledescription="carousel">
  <div role="group" aria-roledescription="slide" aria-label="Slide 1 of 6">
    {/* slide content */}
  </div>
</div>
  • role="region" with aria-label makes the carousel a named landmark
  • Each slide has role="group" and aria-roledescription="slide" per the ARIA carousel pattern
  • aria-label="Slide N of M" on each slide informs screen reader users of position

Hidden slides

Slides outside the visible window have aria-hidden={true} so screen readers don't announce off-screen content.

Keyboard interaction

KeyAction
TabNavigate to previous button, dot indicators, next button
Enter / SpaceActivate a dot or arrow button
Arrow keysNot implemented on the carousel itself — use Tab to navigate controls
  • ImageGallery — use instead when the content is a single-purpose photo set rather than mixed card content.