// preview in
saved for every page

Carousel

Shows one slide at a time from a short set, like news, tour steps or reviews, with previous and next buttons and a row of dots. Anything people must read belongs on the page, not on slide 3.

Pattern WAI-ARIA CarouselClient componentSource ↗
minimal · light · #3fa34d

New

Recurring invoices

Send the same invoice every month, on the day you choose.

autoPlay
showAutoPlayToggle

Installation

Set up Camaleo once (Installation), then import what you need. It runs on the client, because it keeps the current slide.

import { Carousel, CarouselSlide } from "@camaleo/react";

Anatomy

A <section> with the slides, then a row of controls. CarouselSlide is an optional layout for each slide; any element works. Every part has a data-slot you can target from CSS.

Examples

Every example is a real file you can copy. They all wear the skin, mode and brand from the bar above.

minimal · light · #3fa34d

New

Recurring invoices

Send the same invoice every month, on the day you choose.

Step 1

Connect your bank

Pick your bank and sign in once. We only read transactions.

Steps people jump between

Each dot is a tab: Tab reaches the row once, and the arrow keys move between slides. Hide the Play button with showAutoPlayToggle={false} when people read at their own pace.

New

Recurring invoices

Send the same invoice every month, on the day you choose.

Rotation people start

Keep autoPlay off and leave the Play button: people who want the slides to move press it, and Pause stops them. Rotation never runs when the system asks for reduced motion.

Thu, Nov 14 · 9:00 AM

Design tokens at scale

Ana Ribeiro, Nubank

Room 2

Every part of a slide

CarouselSlide lays out kicker, title, description and badge. Put the date or category in the kicker, so the title stays short enough for a phone.

Close the month in minutes

Match every transaction to a category before the 5th.

Your own slide content

Any element can be a slide. Start it with a heading, because the slide's own name is only its position, like "2 of 3".

Step 1

Connect your bank

Pick your bank and sign in once. We only read transactions.

Step 1 of 4

React to the slide

Move through the steps, then press Start over. Control activeIndex when the page must know the slide, like for a step counter or a finish button.

Starter

1 user, 50 invoices a month.

$9/mo

Names in your language

Screen readers hear each slide as "2 of 3, slide". Pass slideLabel, slideRoleDescription and the button labels to say "Plan 2 of 3" in the page's language.

In context

Carousels usually sit in a card or a page section, next to content that is always visible. These are whole pieces of UI you can copy, in the skin you picked.

Getting started

Step 1

Connect your bank

Pick your bank and sign in once. We only read transactions.

Getting started tourCard · Carousel · Button

What customers say

“We closed March in two days instead of a week.”

Carla Mendes, CFO at Pátio Foods

Customer reviewsCard · Carousel · Avatar

This week's deals

Until Sunday

Noise-cancelling headphones

From $299 to $219.

27% off
Store dealsCard · Carousel · Badge · Button

Guidelines

Recurring invoices

Send the same invoice every month, on the day you choose.

DoThree to five slides.

People rarely go past the third slide, so a short set gets seen and the dots stay easy to tell apart.

Recurring invoices

Send the same invoice every month, on the day you choose.

Don’tA slide for every message.

Eight dots look the same, and the last slides are only seen by people who click through all of them.

“We closed March in two days instead of a week.”

Carla Mendes, CFO at Pátio Foods

DoA title on every slide.

People scanning, and screen reader users jumping by heading, know what a slide is about before reading it.

We closed March in two days instead of a week, and the team finally stopped asking finance for spreadsheets every Friday afternoon.

Don’tSlides that are only a paragraph.

Without a title, people have to read the whole slide to decide if it matters to them.

Props

PropTypeDefaultDescription
activeIndexnumber—Index of the slide on show, from 0 (controlled).
defaultIndexnumber0Index of the slide shown first, from 0 (uncontrolled).
onIndexChange((index: number) => void)—Called with the new index when the slide changes, by a button, a dot or rotation.
autoPlaybooleanfalseStarts rotating on load. It never rotates when the person prefers reduced motion, and it holds while the pointer or focus is inside.
intervalMsnumber5000Time each slide stays during rotation, in milliseconds.
showAutoPlayTogglebooleantrueShows the Play/Pause button, also when autoPlay is off, so people can start rotation themselves.
previousLabelstring"Previous slide"Name of the previous button, read by screen readers.
nextLabelstring"Next slide"Name of the next button, read by screen readers.
playLabelReactNode"Play"Text of the rotation button while stopped.
pauseLabelReactNode"Pause"Text of the rotation button while rotating.
indicatorsLabelstring"Choose slide"Name of the row of dots, read by screen readers.
roleDescriptionstring"carousel"What screen readers call the whole component (aria-roledescription). Translate it on non-English pages.
slideRoleDescriptionstring"slide"What screen readers call each slide, like "plan" or "photo".
slideLabel(index, total) => string(i, total) => `${i} of ${total}`Name of each slide from its position (from 1) and the total. Translate it on non-English pages.
goToSlideLabel(index) => string(i) => `Go to slide ${i}`Name of each dot from its position (from 1).
Also accepts every prop of the underlying primitive and native attributes.
PropTypeDefaultDescription
kickerReactNode—Short line above the title, like a category or a date.
descriptionReactNode—Sentence below the title.
badgeReactNode—Element at the end of the slide, like a Badge or an Avatar.

Both take the attributes of their element: Carousel those of <section> (its aria-label defaults to "Carousel", so always pass one), CarouselSlide those of <div>, with children after the description.

Styling hooks

Restyle it without forking: target the attributes, or set the tokens on a parent, a skin or the carousel itself.

Attributes

data-activeon the slide on show and its dot
aria-selectedtrue on the dot of the slide on show

Tokens it reads

Color

--cml-accent-text--cml-border--cml-border-control--cml-button-outline-bg--cml-button-outline-shadow--cml-card-border--cml-card-shadow--cml-fg--cml-fg-secondary--cml-focus-offset--cml-focus-ring--cml-focus-width--cml-surface-raised

Shape & size

--cml-border-width--cml-radius-control--cml-radius-control-sm--cml-radius-pill--cml-radius-popover

Type & motion

--cml-duration-fast--cml-ease-standard--cml-font-control--cml-font-display--cml-font-label--cml-font-weight-control--cml-font-weight-display

This component only

--cml-carousel-dot-radius--cml-carousel-slide-border--cml-carousel-slide-radius--cml-corner-shape

Accessibility

TabMoves through previous, next, Play/Pause, then the row of dots, which is one stop.
Enter / SpacePresses previous, next or Play/Pause.
← / →In the row of dots, shows the previous or next slide and moves focus to its dot. Also ↑ / ↓.
Home / EndIn the row of dots, shows the first or last slide.
Was this page helpful? · Edit this page on GitHub