Carousel
Horizontal strip of slides with arrows, a dot picker and optional autoplay.
Carousel is a standalone component with a slide marker directive.
import { KuiCarousel, KuiCarouselSlide } from '@kikita-labs/ui';Project one element with kuiCarouselSlide per slide and bind index with a signal. The track is native scroll with scroll-snap, so trackpad and touch swipe come from the browser.
<div class="carousel-example">
<kui-carousel ariaLabel="Product photos" [(index)]="slide">
<div kuiCarouselSlide class="carousel-slide">Slide 1</div>
<div kuiCarouselSlide class="carousel-slide">Slide 2</div>
<div kuiCarouselSlide class="carousel-slide">Slide 3</div>
</kui-carousel>
</div>ariaLabel defaults to the carousel.label message (Slides) and should name the content. It must not contain the word carousel: the region's aria-roledescription="carousel" already announces it. The height comes from the slide content, so set a block-size on the carousel root with ordinary CSS if you need a fixed one.
itemsPerView sets how many slides are visible. The highest reachable index is slideCount - itemsPerView, so the dot picker has exactly that many dots. loop wraps at the edges instead of disabling Prev and Next.
<div class="carousel-example">
<kui-carousel ariaLabel="Two at a time" [itemsPerView]="2" loop>
<div kuiCarouselSlide class="carousel-slide">Slide 1</div>
<div kuiCarouselSlide class="carousel-slide">Slide 2</div>
<div kuiCarouselSlide class="carousel-slide">Slide 3</div>
<div kuiCarouselSlide class="carousel-slide">Slide 4</div>
<div kuiCarouselSlide class="carousel-slide">Slide 5</div>
</kui-carousel>
</div>autoplay advances on autoplayInterval and always shows a Play/Pause control. It pauses while the pointer, focus or a touch is inside the region.
<div class="carousel-example">
<kui-carousel ariaLabel="Autoplay slides" autoplay [autoplayInterval]="4000">
<div kuiCarouselSlide class="carousel-slide">Slide 1</div>
<div kuiCarouselSlide class="carousel-slide">Slide 2</div>
<div kuiCarouselSlide class="carousel-slide">Slide 3</div>
<div kuiCarouselSlide class="carousel-slide">Slide 4</div>
</kui-carousel>
</div> The track's aria-live is off while autoplay is advancing and polite whenever it is paused, so manual navigation is still announced.
showArrows and showDots hide the matching control. draggable (default true) adds mouse drag-to-scroll; false also switches the track to overflow-x hidden.
<div class="carousel-example">
<kui-carousel ariaLabel="Dots only" [showArrows]="false" [draggable]="false">
<div kuiCarouselSlide class="carousel-slide">Slide 1</div>
<div kuiCarouselSlide class="carousel-slide">Slide 2</div>
<div kuiCarouselSlide class="carousel-slide">Slide 3</div>
</kui-carousel>
</div>- Touch swipe and trackpad scroll always work through the native
overflow-x: auto; a debounced scroll listener snapsindexto the nearest slide once scrolling settles. showArrows="false"withshowDots="false"(swipe only) is reachable but not self-sufficient under WCAG 2.5.7 (Dragging Movements).
messages overrides the label, role descriptions, controls and slide names for one instance. It wins over scoped and root messages.
<div class="carousel-example">
<kui-carousel [messages]="messages">
<div kuiCarouselSlide class="carousel-slide">Slide 1</div>
<div kuiCarouselSlide class="carousel-slide">Slide 2</div>
<div kuiCarouselSlide class="carousel-slide">Slide 3</div>
</kui-carousel>
</div>Set defaults.carousel once for the application or for a subtree. Each option resolves as local input > defaults.carousel.<option> > built-in default.
import { provideKikitaUi } from '@kikita-labs/ui';
export const appConfig: ApplicationConfig = {
providers: [
provideKikitaUi({
defaults: {
carousel: {
/* options below */
},
},
}),
],
};| Name | Type | Default | Description |
|---|---|---|---|
| itemsPerView | number | — | Slides visible at once. |
| loop | boolean | — | Wraps around at the first and last slide. |
| autoplay | boolean | — | Advances slides automatically. |
| autoplayInterval | number | — | Delay in ms between automatic slide changes. |
| showArrows | boolean | — | Shows the previous and next arrows. |
| showDots | boolean | — | Shows the pagination dots. |
| draggable | boolean | — | Allows dragging the track with a pointer. |
| previousIcon | KuiIconGlyph | — | Icon of the previous control. Takes precedence over defaults.icons.previous. See Structural Icons. |
| nextIcon | KuiIconGlyph | — | Icon of the next control. Takes precedence over defaults.icons.next. See Structural Icons. |
Set any of these on the component or an ancestor to restyle one part. Each token is optional: when it is not set, the part uses the role or scale token in the default column.
| Name | Type | Default | Description |
|---|---|---|---|
| --kui-carousel-track-focus-ring-color | CSS custom property | --kui-color-focus | Track focus ring color |
| --kui-carousel-dot-focus-ring-color | CSS custom property | --kui-color-focus | Dot focus ring color |
| Name | Type | Default | Description |
|---|---|---|---|
| --kui-carousel-stack-gap | CSS custom property | --kui-space-2 | Stack gap |
| --kui-carousel-dots-gap | CSS custom property | --kui-space-2 | Dots gap |
| --kui-carousel-dot-radius | CSS custom property | --kui-radius-full | Dot corner radius |
Every text the component owns (accessible names, visible words, announcements) is a typed message with an English default. Override it for the application with provideKikitaUi({ messages }), or for a subtree with provideKuiMessages.
| Name | Type | Default | Description |
|---|---|---|---|
| label | string | — | Accessible name of the region when ariaLabel is not set. Default Slides. |
| roleDescription | string | — | Role description of the region. Default carousel. |
| slideRoleDescription | string | — | Role description of one slide. Default slide. |
| previous | string | — | Previous arrow. Default Previous slide. |
| next | string | — | Next arrow. Default Next slide. |
| pause | string | — | Pause button. Default Pause autoplay. |
| resume | string | — | Resume button. Default Resume autoplay. |
| dots | string | — | Accessible name of the dot list. Default Choose slide. |
| goToSlide | KuiMessageFn<{ index: number; total: number; }> | — | Accessible name of one dot. Default Go to slide {index} of {total}. |
| slidePosition | KuiMessageFn<{ index: number; total: number; }> | — | Accessible name of one slide. Default {index} of {total}. |
Inputs verified against @kikita-labs/ui v2.0.0 public typings.
| Name | Type | Default | Description |
|---|---|---|---|
| itemsPerView | number | undefined | undefined | How many slides are visible at once (defaults.carousel.itemsPerView, then 1). Invalid or non-positive static values use 1. The highest reachable index is slideCount - itemsPerView, and the dot picker renders exactly that many dots. |
| loop | boolean | undefined | undefined | Wraps navigation at the edges instead of disabling Prev and Next there. Falls back to defaults.carousel.loop, then false. |
| autoplay | boolean | undefined | undefined | Advances automatically on a timer and always shows Play/Pause; pauses while the pointer, focus or a touch is inside. Falls back to defaults.carousel.autoplay, then false. |
| autoplayInterval | number | undefined | undefined | Autoplay delay between slides in ms (defaults.carousel.autoplayInterval, then 4000). Invalid or non-positive static values use 4000. |
| showArrows | boolean | undefined | undefined | Shows the Prev and Next arrows (defaults.carousel.showArrows, then true). Swipe and scroll work regardless. |
| showDots | boolean | undefined | undefined | Shows the dot picker below the track (defaults.carousel.showDots, then true). Swipe and scroll work regardless. |
| draggable | boolean | undefined | undefined | Adds mouse drag-to-scroll on top of the always-native touch swipe (defaults.carousel.draggable, then true). false also locks wheel and trackpad scroll and removes the track from the tab order. |
| ariaLabel | string | undefined | undefined | Accessible name of the region. Falls back to the carousel.label message (Slides); use a content-specific name that does not contain "carousel". |
| messages | Partial<KuiCarouselMessages> | undefined | undefined | Per-instance text overrides for the label, role descriptions, controls and slide names. They win over scoped and root messages. |
| [(index)] | number | 0 | Index of the first visible slide. A debounced scroll listener snaps it to the nearest slide after a swipe or drag. |
| (indexChange) | number | - | Emitted whenever index changes (model output). |
| [kuiCarouselSlide] | content slot | - | Marks projected slide content: role="group" with aria-roledescription="slide" and an "N of total" name. It has no inputs. |
| --kui-carousel-gap / -radius / -slide-radius | CSS custom properties | - | Gap between slides and the region and slide corner radii. |
| --kui-carousel-bg / -border / -slide-bg | CSS custom properties | - | Region background and border and the slide backdrop. |
| --kui-carousel-control-bg / -control-shadow | CSS custom properties | - | Backdrop circle and shadow of the Prev, Next and Play controls. |
| --kui-carousel-dot-bg / -dot-bg-active / -dot-size | CSS custom properties | - | Colour of the dots, the active dot and the dot size. |
| KuiCarouselOptions | interface | - | Shape of defaults.carousel: itemsPerView, loop, autoplay, autoplayInterval, showArrows, showDots, draggable, previousIcon and nextIcon. |
Carousel follows the tabbed carousel pattern with roving focus on the dots.
- The outer element is
role="region"witharia-roledescription="carousel"and theariaLabel; each slide isrole="group"witharia-roledescription="slide"and anN of totalname. - The dot picker is a
tablistoftabs witharia-selected,aria-controlspointing at the slide id and a roving tabindex; arrow keys,HomeandEndmove focus and selection. - The region also responds to
ArrowLeft,ArrowRight,HomeandEndto change slide, independent of dot focus. - While
draggableis true the scrollable track is a keyboard tab stop (tabindex="0") with a visible focus ring; withdraggable="false"it is not. - Prev, Next, Play and Pause are
kuiIconButtons with a requiredaria-label. At the range boundary (withoutloop) Prev or Next gets the nativedisabledattribute and leaves the tab order. - Play/Pause order and pausing on hover and focus follow the W3C APG auto-rotating carousel.
autoplaywith arrows, dots and dragging all disabled leaves no way to pause by hand, which conflicts with WCAG 2.2.2; use it only for purely decorative rotation.
Documented limits of the installed package.
- There is no per-breakpoint
itemsPerView; it is a plain number. - The carousel has no size prop: it always sizes to its container, and the controls inherit their size from the kit's size and density context.
- A formal assistive-technology review with a real screen reader has not been run, and a narrow mobile viewport was not verified by the library review.