Skip to content
Home Theme Gallery

Carousel

The custom element is <hui-carousel>.

Overview

A labelled region of slides the host rendered, moved by CSS scroll snapping, with real previous and next controls. Autoplay is off unless asked for.

Example

Three slides
Source
<hui-carousel label="Gallery" dots style="width:100%">
<div style="display:grid;place-items:center;height:6rem;background:var(--hui-muted)">One</div>
<div style="display:grid;place-items:center;height:6rem;background:var(--hui-card)">Two</div>
<div style="display:grid;place-items:center;height:6rem;background:var(--hui-accent)">Three</div>
</hui-carousel>

The Go template that renders it:

<hui-carousel label="{{ .Label }}"{{ if .Loop }} loop{{ end }}{{ if .Autoplay }} autoplay="{{ .Autoplay }}"{{ end }}>
{{ range .Slides }}
<div>{{ . }}</div>
{{ end }}
</hui-carousel>

API

Attributes6
Attributes
NameTypeDefaultDescription
orientation"horizontal" | "vertical""horizontal"Scroll axis.
indexnumber0The current slide. Reflected; the server may render one.
loopbooleanfalseWhether the ends wrap.
autoplaymillisecondsabsentAbsent means off, which is the default.
labelstring"Carousel"The region’s accessible name.
dotsbooleanfalseShows a labelled dot per slide.
Properties5
Properties
NameTypeDefaultDescription
orientationstring'horizontal'Reflects to orientation.
indexnumber0Reflects to index.
loopbooleanfalseReflects to loop.
autoplaynumber0Reflects to autoplay when positive.
dotsbooleanfalseReflects to dots.
Events1
Events
NameDescription
hui-carousel-changeThe current slide changed, after index is set. Detail: { index }.
Slots3
Slots
NameDescription
(default)The slides the host rendered.
previousA previous control, if the host wants its own.
nextA next control, if the host wants its own.
::part() hooks6
::part() hooks
NameDescription
viewportThe scroll container, which also takes focus for the arrow keys.
trackThe flex row or column of slides.
previousThe previous button.
nextThe next button.
dotsThe dot group, when dots is set.
dotOne dot button.

States

Looping

loop wraps from the last slide back to the first, so neither control is ever disabled.

Looping
Source
<hui-carousel label="Gallery" loop style="width:100%">
<div style="display:grid;place-items:center;height:5rem;background:var(--hui-muted)">One</div>
<div style="display:grid;place-items:center;height:5rem;background:var(--hui-card)">Two</div>
</hui-carousel>

Server-side mechanics

The server owns the slides and may render an initial index and a loop/autoplay setting. The element is not form-associated and submits nothing. The current slide is viewer-owned: reflected to index and announced with hui-carousel-change. An hx-swap that replaces the carousel re-reads index, and a slide the reader moved to is discarded.

Accessibility

  • The viewport is a labelled role="region" with aria-roledescription="carousel".
  • Each slide is announced with its position through aria-roledescription="slide" and a generated label, unless the host set its own.
  • Autoplay is off unless asked for, and pauses on hover, on focus and under prefers-reduced-motion.

Keyboard

Keyboard
KeysAction
Arrow Left/Right (or Up/Down)Moves one slide.
Home, EndMoves to the first or last slide.
TabReaches the previous, next and dot controls, each named.

Gotchas

  • Slides are light-DOM children; the element moves between them and does not clone or virtualise them.
  • Movement is CSS scroll snap plus scrolling the viewport, so touch and trackpad behaviour is the platform’s.