Carousel
A carousel is a region component for cycling through a set of slides or content items, such as image galleries, product showcases, or testimonial rotators. It provides the semantic container with appropriate ARIA roledescription so assistive technologies announce it as a carousel.
The consumer is responsible for providing the slide content as children and implementing navigation controls (previous/next buttons, pagination dots, autoplay logic, etc.). This headless approach gives full control over navigation behavior, animation, and layout while ensuring accessibility compliance.
Example
Show demo markup
<div class="carousel" role="region" aria-label="Carousel"><div>Slide 1</div></div>
Usage example
<script lang="ts">
import Carousel from "./Carousel.svelte";
</script>
<Carousel label="Photo gallery">
<div role="group" aria-roledescription="slide" aria-label="Slide 1 of 3">
<img src="/photos/1.jpg" alt="Mountain sunset" />
</div>
<div role="group" aria-roledescription="slide" aria-label="Slide 2 of 3">
<img src="/photos/2.jpg" alt="Coastline" />
</div>
<div role="group" aria-roledescription="slide" aria-label="Slide 3 of 3">
<img src="/photos/3.jpg" alt="Forest" />
</div>
</Carousel>
Show Svelte source
// In your Svelte component:
import Carousel from "lily-design-system-svelte-headless/components/Carousel/Carousel.svelte";
<Carousel>
<!-- content -->
</Carousel>
Usage
<Carousel label="Customer testimonials">
<div role="group" aria-roledescription="slide" aria-label="Slide 1 of 3">
<blockquote>
<p>"The service transformed how we manage patient records."</p>
<cite>Dr Sarah Mitchell, GP</cite>
</blockquote>
</div>
<div role="group" aria-roledescription="slide" aria-label="Slide 2 of 3">
<blockquote>
<p>"Setup took less than a day and the team was incredibly helpful."</p>
<cite>James O'Brien, Practice Manager</cite>
</blockquote>
</div>
<div role="group" aria-roledescription="slide" aria-label="Slide 3 of 3">
<blockquote>
<p>"We reduced administrative time by 40% in the first month."</p>
<cite>Nurse Karen Phillips</cite>
</blockquote>
</div>
</Carousel>
<Carousel label="Featured articles">
<div role="group" aria-roledescription="slide" aria-label="Slide 1 of 2">
<Image src="/images/article-1.jpg" alt="Accessible design patterns" />
<h3>Building Accessible Forms</h3>
<p>Learn how to create forms that work for everyone.</p>
</div>
<div role="group" aria-roledescription="slide" aria-label="Slide 2 of 2">
<Image src="/images/article-2.jpg" alt="Component composition" />
<h3>Component Composition Patterns</h3>
<p>How to combine headless components for complex UIs.</p>
</div>
</Carousel>
Props
label: string (required) -- accessible name for the carousel region, applied via aria-label.
children: slot (required) -- slide content to render inside the carousel container.
...restProps: unknown -- additional attributes spread onto the container <div>.
Keyboard Interactions
None -- this component is a passive container. The consumer should implement keyboard navigation for slide controls (e.g., previous/next buttons respond to Enter and Space, arrow keys for slide navigation).
ARIA
role="region" -- identifies the carousel as a landmark region so screen readers can navigate to it.
aria-roledescription="carousel" -- overrides the default "region" announcement with "carousel" for clearer context.
aria-label -- provides an accessible name describing the carousel content.
When to Use
- Use for cycling through a set of related content items, such as testimonials, featured articles, or image galleries
- Use when screen space is limited and content can be browsed sequentially
- Use for showcasing a curated set of promotions, portfolio pieces, or product highlights
- Use when the content items are of equal importance and none is critical on its own
When Not to Use
- Do not use for critical content that users must not miss -- carousels are often ignored or skipped
- Do not use when all items need to be visible simultaneously -- use a grid of Cards instead
- Do not use for navigation -- use TabBar or ContentsNav for switching between content panels
- Do not use for a single content item -- use Hero or Card instead
Headless
This headless Carousel component provides the semantic container with role="region", aria-roledescription="carousel", and aria-label for screen reader identification. The consumer provides all visual styling, slide navigation controls (previous/next buttons, pagination dots), autoplay logic, transition animations, and slide layout.
Styles
The consumer provides all CSS styling. The component renders with a .carousel class for targeting. No default styles are included — this is a fully headless component.
Testing
- Verify the component renders a
<div> element with class carousel
- Verify role="region"` -- identifies the carousel as a landmark region so screen readers can navigate to it.
- Verify aria-label` -- provides an accessible name describing the carousel content.
- Verify pass-through attributes are applied
Advice
- Designers: Provide clear navigation indicators (dots or arrows) so users understand there is more content to view. Avoid autoplay or provide a visible pause control.
- Developers: Mark each slide with
role="group" and aria-roledescription="slide" with an aria-label indicating position (e.g., "Slide 1 of 5"). Implement keyboard navigation for slide controls.
Implementation Notes
- Renders a
<div> with role="region" and aria-roledescription="carousel" to communicate the carousel pattern to screen readers.
- The
aria-label prop provides an accessible name for the region.
- Slide content is passed via the
children slot, allowing any markup structure.
- Spreads
restProps onto the container for consumer customization.
- No internal state management for active slide; consumers manage slide state externally.
Related components
photo-pack — see components.tsv
scroller — see components.tsv
horizontal-scroller — see components.tsv
image — an image element with alt text
References
- WAI-ARIA Carousel Pattern: https://www.w3.org/WAI/ARIA/apg/patterns/carousel/
- WAI-ARIA Authoring Practices Carousel: https://www.w3.org/WAI/tutorials/carousels/
Canonical contract
Generated from this component's canonical metadata — the machine-checked source the implementations are held to.
Metadata
- Component: carousel
- PascalCase: Carousel
- Description: a slideshow for cycling through content items
- Status: beta — implemented and unit-tested in all seven frameworks with an axe-clean demo page; not yet exercised in composed flows
- HTML tag: <div>
- CSS class: .carousel
- Interactive: no
ARIA
role="region" -- identifies the carousel as a landmark region so screen readers can navigate to it. aria-roledescription="carousel" -- overrides the default "region" announcement with "carousel" for clearer context. aria-label -- provides an accessible name describing the carousel content.
Keyboard
- No keyboard interactions — this is a passive element
Props
label: string (required) -- accessible name for the carousel region, applied via aria-label. children: slot (required) -- slide content to render inside the carousel container. ...restProps: unknown -- additional attributes spread onto the container <div>.