Components/Surfaces/Carousel
COMPONENT30.30

Carousel

Scroll-snap carousel over a semantic section — no carousel library. Dots, arrows and keyboard paging wired by <mo-carousel>.


INSTALL

1pnpm dlx @sayagodev/mo add carousel

Or import the files from the package (no copy):

1import "@sayagodev/mo/css/carousel.css";2import "@sayagodev/mo/js/carousel.js";

EXAMPLES

Default

Slide one

Native scroll-snap carousel — no Embla, no dependencies.

Swipe, wheel or use the arrows. The dots track the position.

Slide two

Each slide snaps to the start edge of the track.

Slides are plain elements carrying data-carousel-slide.

Slide three

Buttons disable at either end of the carousel.

Arrow keys page while the track is focused.

Slide four

Slides can hold anything — cards, media, forms.

This one holds a .card article, like shadcn's demos.

Slide five

The last slide. The next button is disabled here.

mo-carousel-change fires after each scroll settles.

Multiple

One

data-size="lg" gives each slide a 50% basis.

Two

Two slides are visible at a time.

Three

Snap points still land on slide starts.

Four

Mixing sizes in one track is fine.

Five

Custom bases via --mo-carousel-basis.

Six

The last slide of the track.

Slide sizes

Default

Slides are 100% wide unless sized.

data-size="sm"

An 80% basis — a peek of the next slide.

data-size="lg"

A 50% basis shows the next half.

Sized again

Bases can vary per slide.

Full width

Back to the 100% default.

Spacing

One

data-spacing="tight" halves the track gap.

Two

Two slides visible, 0.5rem apart.

Three

Snap points still land on slide starts.

Four

Override further via --mo-carousel-gap.

Five

The last slide of the tight track.

Vertical

One

data-orientation="vertical" pages on the y axis.

Two

The track becomes a column with a fixed height.

Three

ArrowUp / ArrowDown page when focused.

Four

Height via --mo-carousel-height (default 20rem).

Five

Snap points land on slide starts.

USAGE

1<mo-carousel>2  <section data-carousel aria-roledescription="carousel" aria-label="Highlights">3    <div data-carousel-track>4      <article class="card" data-carousel-slide></article>5    </div>6    <div data-carousel-controls>7      <button type="button" data-carousel-previous class="icon outline"></button>8      <div data-carousel-dots></div>9      <button type="button" data-carousel-next class="icon outline"></button>10    </div>11  </section>12</mo-carousel>

API

NAMEKINDDESCRIPTION
<mo-carousel>elementOptional orchestrator; stepping, dots, disabled ends, mo-carousel-change
[data-carousel-track]attributeFlex scroller with scroll-snap
[data-carousel-slide]attributeSlide; data-size sm=80% lg=50%
[data-orientation="vertical"]attributeColumn track, y paging
[data-spacing="tight"]attributeTight inter-slide gap, like shadcn p-1 items
--mo-carousel-basis / -size-sm / -size-lgtokenSlide width (sm 80% · lg 50%) and height
--mo-carousel-gap / -gap-tighttokenInter-slide gap and the tight variant
--mo-carousel-dottokenActive dot colour

FILES

src/css/carousel.csssrc/js/carousel.js
Install:mo add carousel

THEMING · PLAYGROUND

This is the exact component from the examples above, wearing a completely different theme. Edit the tokens and --mo-* hooks in the editor — autocomplete knows them all — and the preview obeys in real time. Your CSS always wins.

Tokens & hooks — edit live
Global tokens
--foreground--radius
Component hooks
--mo-carousel-basis--mo-carousel-dot--mo-carousel-gap--mo-carousel-gap-tight--mo-carousel-height--mo-carousel-size-lg--mo-carousel-size-sm

Preview

Rev C shipped

Chassis tolerances tightened.

New seal profile

12% faster cycles.

Your CSS

Try it: type --mo- for the component hooks, or edit any value — the preview obeys in real time.