Carousel
FreeAuto-playing image carousel with dots, lines, numbers or no indicator, prev/next arrows and a slide counter.
Complexity tier: Interactive The primitive bar, plus declared async states, a keyboard model, focus restoration and undo for destructive actions.
import { SvCarouselComponent } from '@styloviz/display';Demo & usage
Basic usage
Usage example — open the gallery for the full interactive demo.
An interactive demo for this component lives in the gallery.
Open live demoMore examples
Looping with number indicator
<sv-carousel [slides]="slides" [autoPlay]="true" [interval]="5000" [loop]="true" indicator="numbers" aspectRatio="16/9" (slideChange)="onSlide($event)" (pausedChange)="onPause($event)" />
Calls to action
<!-- slides = [ { id: 'sale', title: 'Summer sale', image: '/img/sale.webp', cta: 'Shop the sale', ctaLink: '/sale' }, { id: 'news', title: 'Join the newsletter', cta: 'Subscribe' }, ] — a CTA with ctaLink is a link; one without is a button you handle. --> <sv-carousel [slides]="slides" (ctaClick)="onCta($event)" />
When to use
- Cycling through a small set of images or promotional slides.
- You want autoplay with arrows and a choice of indicator styles.
- For browsing many images on demand, use the Image Gallery.
Async states
- loading
- empty
- error
- retry
Inputs
| Name | Type | Default | Description |
|---|---|---|---|
| loading | boolean | false | True while the slides are being fetched. |
| error | SvDataError | string | null | null | Load failure. Use `toSvDataError()` from `@styloviz/core` to normalize an `HttpErrorResponse`. |
| emptyMessage | string | 'No slides to show' | Copy for the no-data state. |
| filtered | boolean | false | True when the emptiness is caused by a filter rather than an empty set. |
| slides | readonly CarouselSlide[] | [] | Slides to display (image, caption, optional link). |
| variant | CarouselVariant | 'default' | Visual variant. `default` slides full-bleed; `fade` cross-fades in place; `card` insets each slide as a rounded, shadowed card; `coverflow` shows the neighbouring slides scaled down either side of the active one. Under `prefers-reduced-motion` every variant keeps its layout but drops the transition. |
| indicator | CarouselIndicator | 'dots' | Indicator style: dots, lines, numbers or none. |
| autoPlay | boolean | false | Auto-advance slides. |
| interval | number | 4000 | Auto-advance interval in ms. |
| loop | boolean | true | Wrap from last slide back to first. |
| arrows | boolean | true | Show prev/next arrows. |
| aspectRatio | string | '16/9' | CSS aspect-ratio for the viewport. |
| pauseOnHover | boolean | true | Pause auto-advance while the carousel is hovered or focused. |
| ariaLabel | string | 'Carousel' | Accessible name for the carousel region. |
| priority | boolean | false | Load the first slide's image eagerly at high fetch priority. Set it when the carousel is above the fold — a hero image is usually the page's Largest Contentful Paint, and a lazy one is fetched only after layout. Later slides stay lazy either way. |
Outputs
| Event | Payload type | Description |
|---|---|---|
| retry | void | The host should re-run the failed load. |
| slideChange | number | Emitted with the active slide index when it changes. |
| pausedChange | boolean | Emitted when the user toggles auto-play; payload is the paused state. |
| ctaClick | CarouselSlide | Emitted with the slide whose call-to-action was activated (click, Enter or Space). A slide with `ctaLink` still navigates; this fires first, so it suits analytics. A slide without one has no other effect — handle it here. |
Wire it to your API
This component is headless about transport: it renders what you give it and reports what the user asks for. Nothing below requires @styloviz/data — drive it from whatever you already use.
Template
Bound to the names this component actually exposes.
<sv-carousel [slides]="data.items()" [loading]="data.loading()" [error]="data.error()" [filtered]="data.filtered()" (retry)="data.reload()" />
Host class
Drive the three async inputs from your own fetch.
// This component reports its state but does not emit a query, so drive // it from your own fetch and bind the three async inputs. readonly items = signal<Row[]>([]); readonly loading = signal(false); readonly error = signal<SvDataError | null>(null); async load(): Promise<void> { this.loading.set(true); this.error.set(null); try { this.items.set(await this.api.fetchRows()); } catch (e) { this.error.set(toSvDataError(e)); } finally { this.loading.set(false); } }
- This component does not emit a query, so it renders what you give it. Fetch on your own trigger and bind `slides`, `loading` and `error`.
- Set `filtered` when a search or filter is active. It is the difference between "you have no orders" and "no orders match this filter" — telling a customer with 4,000 orders the first one reads as a bug.
- Normalize failures with `toSvDataError()` from `@styloviz/core`. It derives `retryable` from the status, so a 404 does not get a "Try again" button that can only fail again.
Full walkthrough: Connecting to a backend.
Customization & theming
- Indicator styles: dots, lines, numbers or none.
- Autoplay with configurable interval, `pauseOnHover`, and a built-in pause/play button.
- Custom slide templates.
Best practices
- Do: Leave `pauseOnHover` on (default) so users can read each slide; a pause/play control also appears during autoplay.
- Don't: Don't hide important content or CTAs solely inside auto-advancing slides.
- Tip: Keep slide counts low (3–6); carousels have low engagement past the first slide.
Accessibility
- Exposed as a `region` with `aria-roledescription="carousel"`; slides are labelled groups and a live region announces changes (silenced while auto-rotating).
- Auto-play pauses on hover and keyboard focus and can be stopped with the pause button (WCAG 2.2.2); ←/→ navigate slides.
- Prev/next, indicators and pause are labelled buttons; the active indicator exposes `aria-current`.
Feedback on Carousel
Spotted a gap in this page, or something that didn't work as described? Comments are GitHub Discussions in the public styloviz/community repo, so posting needs a GitHub account.