Carousel
Slides that scroll sideways one at a time, by buttons, swiping or the arrow keys, built on Embla.
A carousel shows one slide of a series at a time and scrolls to the next by buttons, a swipe or the arrow keys. Use it sparingly: content on a later slide is seen by few readers. It is built on Embla Carousel, whose options and plugins it passes through.
Item 1 of 4
// apps/docs/examples/ui/carousel.tsx'use client';
import {useEffect, useState} from 'react';
import { Card, CardContent,} from '@workspace/active-ui/components/primitives/card';import { Carousel, CarouselContent, CarouselItem, CarouselNext, CarouselPrevious, type CarouselApi,} from '@workspace/active-ui/components/primitives/carousel';
const SLIDES = [ 'Statements go out on 1 November', 'New: the participant portal in German', 'Rates for 2027 are published', 'The annual report 2025 is available',];
/** * Slides that scroll sideways, one at a time: by the buttons, by swiping, * or with the arrow keys while the carousel has focus. `setApi` hands over * Embla's API, here to show the position as text. */export default function CarouselExample() { const [api, setApi] = useState<CarouselApi>(); const [current, setCurrent] = useState(1); useEffect(() => { if (!api) return; const update = () => setCurrent(api.selectedScrollSnap() + 1); update(); api.on('select', update); return () => { api.off('select', update); }; }, [api]); return ( <div className="flex w-full flex-col items-center gap-3 px-12"> <Carousel setApi={setApi} className="w-full max-w-xs" aria-label="News" roleDescription="carousel" slideRoleDescription="slide" > <CarouselContent> {SLIDES.map((text, index) => ( <CarouselItem key={text} aria-label={`${index + 1} of ${SLIDES.length}`} > <Card> <CardContent className="flex aspect-[3/2] items-center justify-center text-center font-medium"> {text} </CardContent> </Card> </CarouselItem> ))} </CarouselContent> <CarouselPrevious label="Previous news item" /> <CarouselNext label="Next news item" /> </Carousel> <p className="text-muted-foreground text-sm" aria-live="polite"> Item {current} of {SLIDES.length} </p> </div> );}Usage#
import { Carousel, CarouselContent, CarouselItem, CarouselNext, CarouselPrevious,} from '@workspace/active-ui/components/primitives/carousel';
<Carousel aria-label="News" roleDescription="carousel" slideRoleDescription="slide"> <CarouselContent> <CarouselItem>โฆ</CarouselItem> <CarouselItem>โฆ</CarouselItem> </CarouselContent> <CarouselPrevious label="Previous news item" /> <CarouselNext label="Next news item" /></Carousel>;Anatomy#
Carousel: the region,role="region".orientation(horizontalorvertical),opts(Embla's options, such aslooporalign),plugins(such as autoplay), andset, which receives Embla's API to read or move the position.Api Carousel: the track.Content Carousel: one slide, full width by default; set aItem basisclass (basis-) to show several.1/ 2 CarouselandPrevious Carousel: round buttons outside the track (Next -left-and12 -right-), disabled at the ends unless the carousel loops. Leave room for them.12 use: the carousel's context for a control of your own (Carousel() scroll,Prev scroll,Next can,Scroll Prev can,Scroll Next api).
What your application provides#
A name for the region (
aria-), and the words a screen reader says for the region and for a slide (label role,Description slide), in your reader's language (required).Role Description labelof the previous and next buttons (required), and a name per slide when the position matters, such as "2 of 4".The position as visible text when it helps, as in the example.
If you add autoplay: a way to pause it.
Accessibility and keyboard#
โandโscroll while the focus is inside the carousel.The buttons are disabled at the ends, so the keyboard cannot move past the first or last slide.
Slides are
role="group"with the slide role description.
API#
Import from @workspace/
Props
- Type
string
What a screen reader calls this region instead of "regio": "carrousel".
Supplied already translated, and required: aria- is spoken literally and is therefore user-visible text, not a technical value.
- Type
string
Same for a single item; Carousel reads it from the context.
- Type
Partial<OptionsType>
Embla's options, such as loop or align; the axis follows orientation.
- Type
"horizontal""vertical"- Default
'horizontal'
The direction the slides scroll in.
- Type
(api: CarouselApi) => void
Receives Embla's API once it is ready, to read or move the position.
Other props, such as the standard attributes of the underlying element, className and ref, are passed through.
Other parts#
CarouselPrevious
Props marked Base UI are behaviour of the Base UI part this component is built on.
Props
- Type
string
The accessible name of the button, such as "Next slide".
- Type
boolean- Default
false
Whether the button should be focusable when disabled.
- Type
"default""icon""icon-lg" "icon-sm" "icon-xs" "lg""sm""xs"null- Default
'icon-sm'
The height and padding. xs, sm, default and lg for a button with text; icon-, icon-, icon and icon- for a square button with only an icon, which then needs an accessible name (aria-).
- Type
"default""destructive""ghost""link""outline""secondary"null- Default
'outline'
The visual weight of the button. default for the main action of a screen or form; outline and secondary for other actions; ghost for a quiet action in a toolbar or a list; destructive for an action that deletes or cannot be undone; link for an action that reads as a link. Every variant but link sinks 1px while pressed; a link-styled action keeps its text and icon in place (button-).
- Type
ComponentRender Fn<โฆ> ReactElement<โฆ>
Allows you to replace the component's HTML element with a different tag, or compose it with another component.
Accepts a React or a function that returns the element to render.
Other props, such as the standard attributes of the underlying element, className and ref, are passed through.
CarouselNext
Props marked Base UI are behaviour of the Base UI part this component is built on.
Props
- Type
string
The accessible name of the button, such as "Next slide".
- Type
boolean- Default
false
Whether the button should be focusable when disabled.
- Type
"default""icon""icon-lg" "icon-sm" "icon-xs" "lg""sm""xs"null- Default
'icon-sm'
The height and padding. xs, sm, default and lg for a button with text; icon-, icon-, icon and icon- for a square button with only an icon, which then needs an accessible name (aria-).
- Type
"default""destructive""ghost""link""outline""secondary"null- Default
'outline'
The visual weight of the button. default for the main action of a screen or form; outline and secondary for other actions; ghost for a quiet action in a toolbar or a list; destructive for an action that deletes or cannot be undone; link for an action that reads as a link. Every variant but link sinks 1px while pressed; a link-styled action keeps its text and icon in place (button-).
- Type
ComponentRender Fn<โฆ> ReactElement<โฆ>
Allows you to replace the component's HTML element with a different tag, or compose it with another component.
Accepts a React or a function that returns the element to render.
Other props, such as the standard attributes of the underlying element, className and ref, are passed through.
Parts that take only their elementโs attributes
Carousel: the attributes of aContent <div>, with className and ref.Carousel: the attributes of aItem <div>, with className and ref.
Functions, hooks and constants
- Type
() => CarouselContext Props
The carousel's context, for a control of your own inside it: scroll, scroll, can, can, api and the orientation. Throws outside a Carousel.
Returns
An object with these fields.
- Type
Partial<OptionsType>
Embla's options, such as loop or align; the axis follows orientation.
- Type
"horizontal""vertical"
The direction the slides scroll in.
- Type
(api: CarouselApi) => void
Receives Embla's API once it is ready, to read or move the position.
- Type
string
What a screen reader calls this region instead of "regio": "carrousel".
Supplied already translated, and required: aria- is spoken literally and is therefore user-visible text, not a technical value.
- Type
string
Same for a single item; Carousel reads it from the context.
- Type
EmblaViewport Ref Type
- Type
EmblaCarousel Type | undefined
- Type
() => void
- Type
() => void
- Type
boolean
- Type
boolean
Types
- Type
type CarouselApi = Use Embla Carousel Type[1];
Resolves to Embla.
This page adapts the Carousel documentation of shadcn/ui (MIT licence) to this package; see Third-party notices.