1. Kikita UI
  2. Components
  3. Data and Identity
  4. Carousel
Skip to content
Kikita UI
  • Installation
  • Theming
  • Tokens
  • Typography
  • Density
  • Accessibility
  • Migrating to 2.0
  • Internationalization
  • Defaults
  • Structural icons
  • Auto Focus
  • Forms
  • AI Support
  • Package Smoke
  • Button
  • Link
  • Icon Button
  • Menu
  • Command Palette
  • Field
  • Input
  • Color Input
  • Select
  • Combobox
  • Date Picker
  • Time Picker
  • Calendar
  • Calendar Range
  • File Upload
  • Segmented
  • Slider
  • Number Input
  • OTP Input
  • Textarea
  • Checkbox
  • Switch
  • Radio
  • Group
  • Badge
  • Loader
  • Skeleton
  • Tooltip
  • Toast
  • Empty State
  • Alert
  • Progress
  • Card
  • Tabs
  • Accordion
  • Breadcrumbs
  • Popover
  • Dialog
  • Media Viewer
  • Drawer
  • Splitter
  • Dropdown
  • Separator
  • Stepper
  • Icon
  • Avatar
  • Table
  • Pagination
  • Line Chart
  • Bar Chart
  • Scatter Chart
  • Donut Chart
  • Carousel
  • Chip
  • Scrollbar
  • Tree
  • Import
  • Usage
  • Items per view and loop
  • Autoplay
  • Controls and dragging
  • Message overrides
  • API
  • Accessibility
  • Known gaps
  • Provider defaults
  • Theming tokens
  • Messages

Data and Identity

Stable - @kikita-labs/ui v2.0.0

Carousel

Horizontal strip of slides with arrows, a dot picker and optional autoplay.

Import

Carousel is a standalone component with a slide marker directive.

carousel.ts
import { KuiCarousel, KuiCarouselSlide } from '@kikita-labs/ui';

Usage

Open in Playground

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.

Slide 1
Slide 2
Slide 3
<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.

Items per view and loop

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.

Slide 1
Slide 2
Slide 3
Slide 4
Slide 5
<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

autoplay advances on autoplayInterval and always shows a Play/Pause control. It pauses while the pointer, focus or a touch is inside the region.

Slide 1
Slide 2
Slide 3
Slide 4
<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.

Controls and dragging

showArrows and showDots hide the matching control. draggable (default true) adds mouse drag-to-scroll; false also switches the track to overflow-x hidden.

Slide 1
Slide 2
Slide 3
<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 snaps index to the nearest slide once scrolling settles.
  • showArrows="false" with showDots="false" (swipe only) is reachable but not self-sufficient under WCAG 2.5.7 (Dragging Movements).

Message overrides

messages overrides the label, role descriptions, controls and slide names for one instance. It wins over scoped and root messages.

Slide 1
Slide 2
Slide 3
<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>

Provider defaults

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 */
        },
      },
    }),
  ],
};
NameTypeDefaultDescription
itemsPerViewnumber — Slides visible at once.
loopboolean — Wraps around at the first and last slide.
autoplayboolean — Advances slides automatically.
autoplayIntervalnumber — Delay in ms between automatic slide changes.
showArrowsboolean — Shows the previous and next arrows.
showDotsboolean — Shows the pagination dots.
draggableboolean — Allows dragging the track with a pointer.
previousIconKuiIconGlyph — Icon of the previous control. Takes precedence over defaults.icons.previous. See Structural Icons.
nextIconKuiIconGlyph — Icon of the next control. Takes precedence over defaults.icons.next. See Structural Icons.

Theming tokens

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.

NameTypeDefaultDescription
--kui-carousel-track-focus-ring-colorCSS custom property--kui-color-focusTrack focus ring color
--kui-carousel-dot-focus-ring-colorCSS custom property--kui-color-focusDot focus ring color
NameTypeDefaultDescription
--kui-carousel-stack-gapCSS custom property--kui-space-2Stack gap
--kui-carousel-dots-gapCSS custom property--kui-space-2Dots gap
--kui-carousel-dot-radiusCSS custom property--kui-radius-fullDot corner radius

Messages

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.

NameTypeDefaultDescription
labelstring — Accessible name of the region when ariaLabel is not set. Default Slides.
roleDescriptionstring — Role description of the region. Default carousel.
slideRoleDescriptionstring — Role description of one slide. Default slide.
previousstring — Previous arrow. Default Previous slide.
nextstring — Next arrow. Default Next slide.
pausestring — Pause button. Default Pause autoplay.
resumestring — Resume button. Default Resume autoplay.
dotsstring — Accessible name of the dot list. Default Choose slide.
goToSlideKuiMessageFn<{ index: number; total: number; }> — Accessible name of one dot. Default Go to slide {index} of {total}.
slidePositionKuiMessageFn<{ index: number; total: number; }> — Accessible name of one slide. Default {index} of {total}.

API

Inputs verified against @kikita-labs/ui v2.0.0 public typings.

NameTypeDefaultDescription
itemsPerViewnumber | undefinedundefinedHow 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.
loopboolean | undefinedundefinedWraps navigation at the edges instead of disabling Prev and Next there. Falls back to defaults.carousel.loop, then false.
autoplayboolean | undefinedundefinedAdvances 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.
autoplayIntervalnumber | undefinedundefinedAutoplay delay between slides in ms (defaults.carousel.autoplayInterval, then 4000). Invalid or non-positive static values use 4000.
showArrowsboolean | undefinedundefinedShows the Prev and Next arrows (defaults.carousel.showArrows, then true). Swipe and scroll work regardless.
showDotsboolean | undefinedundefinedShows the dot picker below the track (defaults.carousel.showDots, then true). Swipe and scroll work regardless.
draggableboolean | undefinedundefinedAdds 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.
ariaLabelstring | undefinedundefinedAccessible name of the region. Falls back to the carousel.label message (Slides); use a content-specific name that does not contain "carousel".
messagesPartial<KuiCarouselMessages> | undefinedundefinedPer-instance text overrides for the label, role descriptions, controls and slide names. They win over scoped and root messages.
[(index)]number0Index 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-radiusCSS custom properties-Gap between slides and the region and slide corner radii.
--kui-carousel-bg / -border / -slide-bgCSS custom properties-Region background and border and the slide backdrop.
--kui-carousel-control-bg / -control-shadowCSS custom properties-Backdrop circle and shadow of the Prev, Next and Play controls.
--kui-carousel-dot-bg / -dot-bg-active / -dot-sizeCSS custom properties-Colour of the dots, the active dot and the dot size.
KuiCarouselOptionsinterface-Shape of defaults.carousel: itemsPerView, loop, autoplay, autoplayInterval, showArrows, showDots, draggable, previousIcon and nextIcon.

Accessibility

Carousel follows the tabbed carousel pattern with roving focus on the dots.

  • The outer element is role="region" with aria-roledescription="carousel" and the ariaLabel; each slide is role="group" with aria-roledescription="slide" and an N of total name.
  • The dot picker is a tablist of tabs with aria-selected, aria-controls pointing at the slide id and a roving tabindex; arrow keys, Home and End move focus and selection.
  • The region also responds to ArrowLeft, ArrowRight, Home and End to change slide, independent of dot focus.
  • While draggable is true the scrollable track is a keyboard tab stop (tabindex="0") with a visible focus ring; with draggable="false" it is not.
  • Prev, Next, Play and Pause are kuiIconButtons with a required aria-label. At the range boundary (without loop) Prev or Next gets the native disabled attribute and leaves the tab order.
  • Play/Pause order and pausing on hover and focus follow the W3C APG auto-rotating carousel. autoplay with 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.

Known gaps

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.

On this page