Skip to content
SuperCoach

Components · Data display

Carousel

Beta

Scrolls through items, such as progress photos.

Goblet squat

3 × 12 reps · Rest 60 s
Keep the dumbbell close to your chest and your heels down.

Romanian deadlift

3 × 10 reps · Rest 90 s
Push your hips back and keep a soft bend in the knees.

Push-up

3 × 15 reps · Rest 60 s
Hands under your shoulders, body in one straight line.

Seated cable row

3 × 12 reps · Rest 60 s
Pull to your lower ribs and squeeze your shoulder blades.

Plank

3 × 45 s · Rest 30 s
Brace your core and don't let your hips drop.

Exercise 1 of 5

When to use

  • To step through items of the same kind where one at a time is the point: the exercise demos in a workout, a client's progress photos in date order.
  • When space is short, such as a card or a mobile screen, and coaches can be expected to look at the items in order.

When not to use

A carousel hides everything but the visible slide. Most people never get past the first one, and screen reader and keyboard users have to work to find the rest. Before using one, check whether all items could just be shown.

  • For content coaches must see or compare: a list, a grid of Cards or a Table. Comparing a week 1 and a week 8 photo is easier side by side than two slides apart.
  • For announcements, promotions or tips that rotate on their own: they are missed, and auto-rotation fails WCAG 2.2.2 unless it can be paused. This component has no autoplay; don't add it.
  • For steps in a form or onboarding: use a stepper with a visible step count, so progress is clear.
  • For a few items that fit on screen: show them.

Anatomy

Goblet squat

3 × 12 reps · Rest 60 s

Push-up

3 × 15 reps · Rest 60 s

Exercise 1 of 2

  1. 1. Region: role="region", aria-roledescription="carousel", with an aria-label
  2. 2. Slide: role="group", aria-roledescription="slide", labelled "1 of 5"
  3. 3. Previous button: hidden label from the UI labels, disabled at the start
  4. 4. Position: "Exercise 1 of 5", a live region (optional, recommended)
  5. 5. Next button: disabled at the end

By default the Previous and Next buttons sit outside the slides, 48px from each side (-start-12, -end-12), so leave that much room around the carousel. To place them below the slides, as in the anatomy, pass className="static translate-y-0".

Variants

3 Aug88.0 kg
17 Aug86.4 kg
31 Aug85.1 kg
14 Sep84.2 kg
28 Sep83.0 kg
12 Oct82.5 kg
VariantUse for
One slide in view (default)Exercise demos: one at a time, with the cue to read.
Several in view (basis-1/2, basis-1/3 on CarouselItem, opts={{ align: "start" }})Progress photos: the coach sees neighbours for context.
Vertical (orientation="vertical")Rarely. A vertical list is almost always better.

States

StateWhat changesToken
First slidePrevious is disabledopacity-(--opacity-disabled)
Last slideNext is disabledopacity-(--opacity-disabled)
Button hoverOutline button fillhover:bg-accent (from Button)
Button focus-visibleRing around the round buttonring-ring/50, 3px
DraggingSlides follow the pointer or finger (Embla)—

Usage guidelines

  • Always show the position ("Exercise 2 of 5") so coaches know how many there are.
  • Keep slides the same height, and keep the controls in the same place on every slide.
  • Put only short content in a slide, with at most one link or button. Long text and forms don't belong in a carousel.
  • Give the carousel a name that says what it holds: "Exercise demos for Upper body A", not "Carousel".

Exercise 2 of 5

Do.The position is written out, and announced when it changes.
Don't.Dots only. They are too small to tap, have no text, and the empty ones are barely visible.

Content guidelines

  • The carousel's label names the set and its owner: "Progress photos, Omar Haddad".
  • Slide labels are positions: "1 of 6". In Arabic, "1 من 6".
  • The position line uses the item's name: "Exercise 2 of 5", "Check-in 3 of 6".
  • Exercise slides: name, dose ("3 × 12 reps · Rest 60 s") and one cue. Units follow Content › Units.
  • Photo slides: the date and the measurement, so the photo is never the only information.

Accessibility

KeyDoes
TabMoves to the Previous and Next buttons, and to anything focusable inside the slides
Enter or Space on a buttonGoes to the previous or next slide
Arrow left / Arrow right (focus anywhere inside the carousel)Previous / next slide. Reversed in RTL: Arrow right goes to the previous slide
  • The root is a region with aria-roledescription="carousel", so screen readers announce it as "Exercise demos for Upper body A, carousel". Without an aria-label the region has no name, so always pass one.
  • Each slide is a group with aria-roledescription="slide". Label it with its position ("1 of 5"); the component doesn't add one.
  • The Previous and Next buttons have hidden labels from lib/ui-labels.tsx: "Previous slide" and "Next slide", or "الشريحة السابقة" and "الشريحة التالية" on Arabic screens. They are 32px round, above the 24px minimum target.
  • Slides out of view are still in the tab order. Embla scrolls a slide into view when something in it gets focus, so keyboard users can reach every item, but keep focusable content in slides to one item.
  • The visible position line is aria-live="polite", so a slide change is announced ("Exercise 2 of 5"). The component doesn't announce changes on its own.
  • The arrow keys are captured on the whole carousel, including any text field inside a slide. Don't put inputs in slides.

RTL

  • The carousel follows the reading direction: Embla gets direction from Radix's Direction provider, so in Arabic the first slide is on the right and the next one comes in from the left.
  • Previous sits on the right and Next on the left (-start-12, -end-12), and their arrows mirror (rtl:-scale-x-100).
  • Arrow keys follow what you see: Arrow left goes to the next slide in RTL.
  • Photos inside slides don't mirror.

Tokens used

Read from components/ui/carousel.tsx at build time, so this list changes when the component does. Opacity modifiers such as /90 are shadcn hover and focus tints on top of the token.

Semantic color tokens used by this component
TokenUtilitiesSuperCoachCoach
  • Radiusrounded-full

The carousel's colors come from the Button (outline variant) and from what you put in the slides.

Props

Also takes every prop of <div>

Carousel props
PropTypeDefault
opts?CarouselOptions—
plugins?CarouselPlugin—
orientation?"horizontal" | "vertical""horizontal"
setApi?(api: CarouselApi) => void—

<CarouselContent>

Also takes every prop of <div>

No props of its own.

<CarouselItem>

Also takes every prop of <div>

No props of its own.

<CarouselPrevious>

Also takes every prop of <Button>

No props of its own.

<CarouselNext>

Also takes every prop of <Button>

No props of its own.

Replaces in coach-admin

The audit found no styles for this component in coach-admin.

The audit searched for carousel, Slick, Swiper and Embla classes and paths. src/reusableComponents/slider/ is not a carousel: it sets a fill width in percent, like a range or progress control.

Card, Avatar, Button, Content.