Carousel

One scrolling core for panels and websites: card sliders, a fade + autoplay hero, a gallery with thumbnails, a KPI strip. Presets set the control layout; the WAI-ARIA carousel pattern, keyboard support, inert off-screen slides, a mandatory pause button and reduced motion come built in. Marquee is a pure-CSS logo band.

Embla Carousel (+ fade, + autoplay) components/carousel.tsx, styles/media.csstheme · material · accent · density · font

Installation

$ pnpm add @vamos-ui/react

The whole kit as one package — get updates by bumping the version. Add the styles to globals.css: @import "@vamos-ui/react/styles.css";

Usage

import { Carousel, CarouselViewport, CarouselSlide, CarouselDots } from "@vamos-ui/react";

<Carousel label="Featured stays" slidesPerView={{ base: 1, md: 2, lg: 3 }}>
  <CarouselViewport>
    {stays.map((s) => <CarouselSlide key={s.id}>…</CarouselSlide>)}
  </CarouselViewport>
  <CarouselDots />
</Carousel>

Keys when focus is inside: ←/→ (↑/↓ vertical), Home, End. RTL flips the arrows and the direction.

No backdrop-filter on slides: only the overlay controls blur (glass budget).

Examples

Hero (fade + autoplay)

preset="hero": glass arrows inside, dots over the image, a pause button first in the tab order. Autoplay pauses on hover and focus and is off under reduced motion.

Slides per breakpoint (KPI strip)

slidesPerView takes a breakpoint map; widths are pure CSS, so the layout is right before hydration. preset="strip" fades the edges.

Vertical

orientation="vertical" with ↑/↓ keys. Set the height with --carousel-height.

Marquee (pure CSS)

No JS, renders with SSR, pauses on hover. Listed once for screen readers; static under reduced motion.

Trusted by 1,200 teams across Türkiye

  • Atlas Lojistik
  • Defne Spa
  • Kalamış Bistro
  • Kargo Hızlı
  • Moda Sahne
  • Pera Dental
  • Bosphorus Yacht Co.
  • Nişantaşı Optik

Controlled, two in sync

index + onIndexChange keep two carousels on the same slide.

API

Carousel

PropTypeDefault
label
Required accessible name (aria-label on the region).
string—
preset
Control layout: hero = full-bleed with glass arrows inside and dots on the image; gallery = thumbnails below; strip = arrows outside, faded edges.
"default" | "gallery" | "hero" | "strip""default"
controls
Arrow placement. Outside arrows hide below 640 px (swipe instead). Keyboard works in every mode.
"inside" | "outside" | "hidden"inside for hero/gallery, else outside
slidesPerView
Slides visible at once (CSS flex-basis). auto lets each slide size itself.
number | "auto" | { base?, sm?, md?, lg?, xl? }1
gap
Space between slides, from --gap.
"none" | "sm" | "md" | "lg""md"
orientation
Vertical uses ↑/↓ and --carousel-height.
"horizontal" | "vertical""horizontal"
loop
Wrap around at the ends.
booleanfalse
align
Snap alignment.
"start" | "center""start"
transition
fade cross-fades one slide per view. Reduced motion: instant.
"slide" | "fade""slide"
autoplay
Advance on a timer (default 6 s). Adds a Play/Pause button; pauses on hover/focus; aria-live off while playing.
boolean | { delay?: number; stopOnInteraction?: boolean }false
index / defaultIndex / onIndexChange
Controlled or uncontrolled selected slide.
number / number / (i) => void— / 0
loading
A skeleton first slide while there are no slides yet.
booleanfalse
options / plugins
Escape hatch to the engine.
EmblaOptions / EmblaPlugin[]—
setApi
Receives the engine API once ready.
(api) => void—
labels
previous, next, goTo, pause, play, slideOf, counter… (dictionary namespace carousel).
Partial<CarouselLabels>—

CarouselViewport

PropTypeDefault
arrows
Built-in prev/next on the stage (hidden with one slide or controls="hidden").
booleantrue
playPause
Built-in pause button with autoplay. Turn off only when you render CarouselPlayPause yourself.
booleantrue
empty
Shown when there are no slides.
ReactNode"Nothing to show yet"
containerClassName
Class for the flex track.
string—

CarouselSlide

PropTypeDefault
…div props
role="group", aria-roledescription="slide", labelled "3 of 7"; inert while off-screen.
HTMLAttributes—

Controls

PropTypeDefault
CarouselPrev / CarouselNext
Disabled at the edges unless loop. Glass buttons over images.
IconButton props + label?—
CarouselDots
One button per snap; aria-current on the active one.
HTMLAttributes—
CarouselThumbs
Thumbnail buttons; the selected one gets a --ring border.
{ items: (string | { src; alt? })[]; aspect?: number }—
CarouselPlayPause
Renders only while autoplay is configured.
IconButton props—
CarouselCounter
"3 / 7" in the locale's digits (with a full sentence for screen readers).
HTMLAttributes—
useCarousel()
State and commands inside a Carousel.
→ { api, index, count, canPrev, canNext, playing, scrollTo, scrollPrev, scrollNext, play, pause, toggle }—

Marquee

PropTypeDefault
label
Accessible name of the list.
string—
duration
Seconds per loop.
number40
reverse
Scroll the other way.
booleanfalse
pauseOnHover
Pause while hovered or focused.
booleantrue
fade
Fade the edges.
booleantrue
gap
Space between items.
"sm" | "md" | "lg""lg"
controls
Pause control (a native checkbox) for moving content longer than five seconds (WCAG 2.2.2).
booleantrue
pauseLabel
Accessible name of the pause control.
string"Pause scrolling"