Skip to content

Carousel

Data displaySince 0.9.0
import { Carousel } from '@absoluteui/components/carousel';
import '@absoluteui/components/button/style.css';

Using Angular? See Carousel for Angular.

Shows one slide at a time from a set, such as featured items, an onboarding tour, or images, following the WAI-ARIA APG carousel pattern. The carousel is a named region with the role description “carousel”; each slide is a group labelled “N of M”; previous, next, and slide picker buttons move between slides; and slides that are not shown are inert, so focus never lands in a hidden slide. Autoplay is off by default. When it is on, a pause button comes first, rotation pauses on hover and focus, and it does not start for users who prefer reduced motion.

  • A few related items of equal weight that do not all need to be visible at once.
  • A short step-through such as an onboarding tour.
  • Important content every user must see (most users never see slides after the first).
  • Many items: use a list or a grid.
  • Navigation between views: use Tabs.
import { Carousel } from '@absoluteui/components/carousel';
import { Card } from '@absoluteui/components/card';
const slides = [
['Spring sale', '20% off garden furniture until Sunday.'],
['New arrivals', 'The summer collection is here.'],
['Free delivery', 'On every order over 50 EUR.'],
].map(([title, content]) => {
const host = document.createElement('div');
Card.create(host, { title: title ?? '', content: content ?? '' });
return { content: host, label: title ?? '' };
});
const host = document.createElement('section');
document.body.append(host);
Carousel.create(host, { label: 'Featured', slides, loop: true });
import { Carousel } from '@absoluteui/components/carousel';
const host = document.createElement('section');
document.body.append(host);
// Rotation pauses on hover and focus, and does not start for users who prefer reduced motion.
Carousel.create(host, {
label: 'Announcements',
autoplay: 6000,
loop: true,
slides: [
{ content: 'The office is closed on Monday for the public holiday.' },
{ content: 'Benefits enrollment closes on the 30th.' },
{ content: 'Welcome to the 12 people who joined this month.' },
],
});
import { Carousel } from '@absoluteui/components/carousel';
import '@absoluteui/components/button/style.css';
import '@absoluteui/components/carousel/style.css';
const host = document.querySelector<HTMLElement>('#quotes');
if (host) Carousel.create(host, { label: 'Customer quotes', loop: true, slides: [{ content: 'Fast and reliable.' }, { content: 'Great support.' }] });
import { Carousel, type CarouselChangeDetail } from '@absoluteui/components/carousel';
const host = document.querySelector<HTMLElement>('#tour');
if (host) {
Carousel.create(host, { label: 'Product tour', slides: [{ content: 'Welcome' }, { content: 'Create a project' }, { content: 'Invite your team' }] });
host.addEventListener('aui-change', (event) => {
const { index } = (event as CustomEvent<CarouselChangeDetail>).detail;
host.dataset.step = String(index + 1);
});
}
<section class="aui-carousel" role="region" aria-roledescription="carousel" aria-label="Featured">
<button class="aui-carousel__pause">Pause</button> (autoplay only)
<div class="aui-carousel__viewport" aria-live="polite|off">
<div class="aui-carousel__track">
<div class="aui-carousel__slide" role="group" aria-roledescription="slide" aria-label="1 of 3: Spring sale">content</div>
<div class="aui-carousel__slide" ... inert>...</div>
</div>
</div>
<div class="aui-carousel__controls">
<button class="aui-carousel__prev" aria-label="Previous slide"></button>
<div class="aui-carousel__picker" role="group" aria-label="Slides"><button class="aui-carousel__dot" aria-label="Go to slide 1" aria-current="true"></button> ...</div>
<button class="aui-carousel__next" aria-label="Next slide"></button>
</div>
</section>
Carousel.create(host: HTMLElement, options: CarouselOptions): Carousel

Global configuration key: carousel (see Configuration).

Option Type Default Description
label string Accessible name of the carousel. Required.
slides readonly CarouselSlide[] Slides: { content: Node | string, label? } (1 to 100). Required.
index number "0" Current slide (0-based).
loop boolean "false" Wrap from the last slide to the first and back.
autoplay number | null "null" Rotation interval in milliseconds (at least 2000), or null.
showPicker boolean "true" Show the slide picker buttons. Globally configurable.
locale string "en-US" Locale of the control labels and slide positions. Globally configurable. Inherited from common configuration.
Property Type Description
host HTMLElement The host element (role=region).
index number Current slide (0-based).
rotating boolean Whether automatic rotation is running now.
options Readonly<CarouselOptions> Current options.
Method Description
goTo(index: number): void Show a slide (no event); clamped, or wrapped with loop.
next(): void Show the next slide (no event).
previous(): void Show the previous slide (no event).
update(options: Partial<CarouselOptions>): void Merge and apply options.
destroy(): void Stop rotation and remove rendering, attributes, and listeners.
Event Detail Bubbles Cancelable Description
aui-change CarouselChangeDetail Yes No The user moved to another slide: { index }.
Area Description
slides Each slide’s content (Node or text).

All rules live in the aui.components cascade layer, so application styles override them without specificity battles.

Class Purpose
aui-carousel Host (role=region, roledescription carousel).
aui-carousel--autoplay | --animated Autoplay configured; transitions enabled after the first move.
aui-carousel__pause Pause/play button (first; autoplay only).
aui-carousel__viewport Clips the track; the live region.
aui-carousel__track Slides side by side.
aui-carousel__slide | __slide--current A slide (role=group, roledescription slide) and the current one.
aui-carousel__controls Previous, picker, next.
aui-carousel__prev | __next Previous and next buttons.
aui-carousel__picker Slide picker group.
aui-carousel__dot | __dot--current A picker button and the current one.

Tokens this stylesheet reads (verified in CI). Override them in a theme or with the Theme Designer.

--aui-color-primary | --aui-duration-fast | --aui-easing-standard | --aui-radius-md | --aui-radius-pill | --aui-space-1 | --aui-space-2 | --aui-space-3

interface CarouselConfig { showPicker: boolean }
interface CarouselSlide { content: Node | string; label?: string }
interface CarouselOptions extends Partial<CarouselConfig> {
label: string;
slides: readonly CarouselSlide[];
index?: number;
loop?: boolean;
autoplay?: number | null;
locale?: string;
}
interface CarouselChangeDetail { index: number }

Pattern: WAI-ARIA APG Carousel (basic, with slide picker buttons): region with aria-roledescription ‘carousel’, slides as groups with aria-roledescription ‘slide’ and ‘N of M’ labels, rotation control first.

Key Context Action
Tab Carousel Pause button (with autoplay), the current slide’s content, previous, picker buttons, next.
Enter / Space Buttons Activate.
Element Role
host region (aria-roledescription ‘carousel’)
slide group (aria-roledescription ‘slide’)
pause, previous, next, picker button (native)
picker group
Attribute Element Value
aria-label host the label option
aria-label slide ‘N of M’ (plus the slide label)
aria-live viewport off while rotating automatically; polite otherwise
aria-current current picker button true
aria-label pause button ‘Stop automatic slide show’ or ‘Start automatic slide show’
inert inactive slides present (not focusable, not read)

Focus inside the carousel (or hovering it) pauses rotation; moving slides never moves focus.

Criterion Level Note
1.3.1 Info and Relationships A
2.1.1 Keyboard A
2.2.2 Pause, Stop, Hide A
2.3.3 Animation from Interactions AAA
2.4.3 Focus Order A
2.5.8 Target Size (Minimum) AA
4.1.2 Name, Role, Value A
4.1.3 Status Messages AA

Automated test results: Accessibility and compliance.

  • Autoplay is off by default; when on, the pause button is the first element (WCAG 2.2.2), and users who prefer reduced motion start paused.
  • Picker dots keep a 24px target and the current one is filled, not only recolored.
  • Manual screen-reader verification (NVDA, JAWS, VoiceOver) is pending.

First, middle, or last slide; loop; autoplay rotating or paused; a single slide (controls hidden).

From Trigger To
slide N Next, a picker button, or a swipe another slide; aui-change
rotating hover, focus inside, or Pause paused (hover and focus resume when they end; Pause until Play)
any goTo() / update({ index }) the given slide, no event
  • Moving content for more than five seconds needs a way to pause it (WCAG 2.2.2): the pause button is always there with autoplay.
  • Users who prefer reduced motion start paused; the animation setting “none” disables rotation entirely.
  • Changing slides never moves focus; announcements come from the live region.
  • The e2e axe run covers three themes; manual screen-reader verification is pending.

Slides take the full width; on touch screens a horizontal swipe moves between slides; the controls sit under the slides.

The track and swipe directions mirror: the next slide comes from the left.

The picker dot color is in the contrast gate; the current dot is filled, not only recolored. Forced colors use ButtonText and Highlight.

configureAbsoluteUI({ components: { carousel: { showPicker: false } } });

Instance showPicker and locale override configuration; configuration changes re-render existing carousels.

Previous and next use the chevron-left and chevron-right icons (they follow the icon provider).

String content is rendered as text; Node content is inserted as given.

No persistence, network access, or telemetry.

All slides stay in the DOM (inert when not shown); moving changes one CSS custom property and the inert flags.

Up to 100 slides; intended for a handful.

  • Without loop, previous is disabled on the first slide and next on the last.
  • With a single slide, the controls are hidden.
  • update({ slides }) keeps the current index when it still exists, otherwise the last slide.
Code Category Cause
CAROUSEL_OPTIONS configuration Blank label, no slides or more than 100, slide content that is not a Node or string, an index out of range, or autoplay under 2000 ms.
CFG_INVALID_VALUE / CFG_UNKNOWN_OPTION configuration Invalid or unknown configuration.

Invalid options throw before the host is modified; an invalid update() leaves the previous state intact.

  • One slide is shown at a time.
  • Swiping is for touch and pen; mouse users use the buttons.
  • Manual screen-reader verification is pending.
  • Several slides per view or free scrolling: use Scroll Area with a horizontal strip.
  • Autoplay intervals shorter than 2 seconds.