Skip to main content
0.78.3
View Zag.js on Github
Join the Discord server

Carousel

an accessible carousel component that leverages native CSS Scroll Snap for smooth, performant scrolling between slides.

Properties

Features

  • Uses native CSS Scroll Snap.
  • Supports horizontal and vertical orientations.
  • Supports alignment of slides (start, center or end alignment).
  • Show multiple slides at a time.
  • Supports looping and auto-playing.
  • Supports custom spacing between slides.

Installation

To use the carousel machine in your project, run the following command in your command line:

npm install @zag-js/carousel @zag-js/react # or yarn add @zag-js/carousel @zag-js/react

This command will install the framework agnostic carousel logic and the reactive utilities for your framework of choice.

Anatomy

To set up the carousel correctly, you'll need to understand its anatomy and how we name its parts.

Each part includes a data-part attribute to help identify them in the DOM.

Usage

First, import the carousel package into your project

import * as carousel from "@zag-js/carousel"

The carousel package exports two key functions:

  • machine — The state machine logic for the carousel widget.
  • connect — The function that translates the machine's state to JSX attributes and event handlers.

You'll also need to provide a unique id to the useMachine hook. This is used to ensure that every part has a unique identifier.

Next, import the required hooks and functions for your framework and use the carousel machine in your project 🔥

import * as carousel from "@zag-js/carousel" import { normalizeProps, useMachine } from "@zag-js/react" const items = [ "https://tinyurl.com/5b6ka8jd", "https://tinyurl.com/7rmccdn5", "https://tinyurl.com/59jxz9uu", ] export function Carousel() { const [state, send] = useMachine( carousel.machine({ id: "1", slideCount: items.length }), ) const api = carousel.connect(state, send, normalizeProps) return ( <div {...api.getRootProps()}> <div {...api.getControlProps()}> <button {...api.getPrevTriggerProps()}>Prev</button> <button {...api.getNextTriggerProps()}>Next</button> </div> <div {...api.getItemGroupProps()}> {items.map((image, index) => ( <div {...api.getItemProps({ index })} key={index}> <img src={image} alt="" style={{ height: "300px", width: "100%", objectFit: "cover" }} /> </div> ))} </div> <div {...api.getIndicatorGroupProps()}> {api.pageSnapPoints.map((_, index) => ( <button {...api.getIndicatorProps({ index })} key={index} /> ))} </div> </div> ) }

To create a vertical carousel, set the orientation property in the machine's context to vertical.

const [state, send] = useMachine( carousel.machine({ orientation: "vertical", }), )

Setting the initial slide

To set the initial slide of the carousel, pass the page property to the machine's context.

The page corresponds to the scroll snap position index based on the layout. It does not necessarily correspond to the index of the slide in the carousel.

const [state, send] = useMachine( carousel.machine({ page: 2, }), )

Setting the number of slides to show at a time

To customize number of slides to show at a time, set the slidesPerPage property in the machine's context. The value must be an integer.

const [state, send] = useMachine( carousel.machine({ slidesPerPage: 2, }), )

Setting the number of slides to move at a time

To customize number of slides to move at a time, set the slidesPerMove property in the machine's context. The value must be an integer or auto.

If the value is auto, the carousel will move the number of slides equal to the number of slides per page.

const [state, send] = useMachine( carousel.machine({ slidesPerMove: 2, }), )

Ensure the slidesPerMove is less than or equal to the slidesPerPage to avoid skipping slides.

To allow looping of slides, set the loop property in the machine's context to true.

const [state, send] = useMachine( carousel.machine({ loop: true, }), )

Setting the gap between slides

To customize spacing between slides, set the spacing property in the machine's context to a valid CSS unit.

const [state, send] = useMachine( carousel.machine({ spacing: "16px", }), )

Listening for page changes

When the carousel page changes, the onPageChange callback is invoked.

const [state, send] = useMachine( carousel.machine({ onPageChange(details) { // details => { page: number } console.log("selected page:", details.page) }, }), )

To allow dragging the carousel with the mouse, set the allowMouseDrag property in the machine's context to true.

const [state, send] = useMachine( carousel.machine({ allowMouseDrag: true, }), )

To allow the carousel to autoplay, set the autoplay property in the machine's context to true.

const [state, send] = useMachine( carousel.machine({ autoplay: true, }), )

Alternatively, you can configure the autoplay interval by setting the delay property in the machine's context.

const [state, send] = useMachine( carousel.machine({ autoplay: { delay: 2000 }, }), )

Styling guide

Earlier, we mentioned that each carousel part has a data-part attribute added to them to select and style them in the DOM.

[data-part="root"] { /* styles for the root part */ } [data-part="item-group"] { /* styles for the item-group part */ } [data-part="item"] { /* styles for the root part */ } [data-part="control"] { /* styles for the control part */ } [data-part="next-trigger"] { /* styles for the next-trigger part */ } [data-part="prev-trigger"] { /* styles for the prev-trigger part */ } [data-part="indicator-group"] { /* styles for the indicator-group part */ } [data-part="indicator"] { /* styles for the indicator part */ } [data-part="autoplay-trigger"] { /* styles for the autoplay-trigger part */ }

Active state

When a carousel's indicator is active, a data-current attribute is set on the indicator.

[data-part="indicator"][data-current] { /* styles for the indicator's active state */ }

Methods and Properties

The carousel's api exposes the following methods and properties:

Machine Context

The carousel machine exposes the following context properties:

  • idsPartial<{ root: string; item(index: number): string; itemGroup: string; nextTrigger: string; prevTrigger: string; indicatorGroup: string; indicator(index: number): string; }>The ids of the elements in the carousel. Useful for composition.
  • translationsIntlTranslationsThe localized messages to use.
  • slidesPerPagenumberThe number of slides to show at a time.
  • slidesPerMovenumber | "auto"The number of slides to scroll at a time. When set to `auto`, the number of slides to scroll is determined by the `slidesPerPage` property.
  • autoplayboolean | { delay: number; }Whether to scroll automatically. The default delay is 4000ms.
  • allowMouseDragbooleanWhether to allow scrolling via dragging with mouse
  • loopbooleanWhether the carousel should loop around.
  • pagenumberThe index of the active page.
  • spacingstringThe amount of space between items.
  • paddingstringDefines the extra space added around the scrollable area, enabling nearby items to remain partially in view.
  • onPageChange(details: PageChangeDetails) => voidFunction called when the page changes.
  • inViewThresholdnumber | number[]The threshold for determining if an item is in view.
  • snapType"proximity" | "mandatory"The snap type of the item.
  • slideCountnumberThe total number of slides. Useful for SSR to render the initial ating the snap points.
  • onDragStatusChange(details: DragStatusDetails) => voidFunction called when the drag status changes.
  • onAutoplayStatusChange(details: AutoplayStatusDetails) => voidFunction called when the autoplay status changes.
  • dir"ltr" | "rtl"The document's text/writing direction.
  • idstringThe unique identifier of the machine.
  • getRootNode() => ShadowRoot | Node | DocumentA root node to correctly resolve document in custom environments. E.x.: Iframes, Electron.
  • orientationOrientationThe orientation of the element.

Machine API

The carousel api exposes the following methods:

  • pagenumberThe current index of the carousel
  • pageSnapPointsnumber[]The current snap points of the carousel
  • isPlayingbooleanWhether the carousel is auto playing
  • isDraggingbooleanWhether the carousel is being dragged. This only works when `draggable` is true.
  • canScrollNextbooleanWhether the carousel is can scroll to the next view
  • canScrollPrevbooleanWhether the carousel is can scroll to the previous view
  • scrollToIndex(index: number, instant?: boolean) => voidFunction to scroll to a specific item index
  • scrollTo(page: number, instant?: boolean) => voidFunction to scroll to a specific page
  • scrollNext(instant?: boolean) => voidFunction to scroll to the next page
  • scrollPrev(instant?: boolean) => voidFunction to scroll to the previous page
  • getProgress() => numberReturns the current scroll progress as a percentage
  • play() => voidFunction to start/resume autoplay
  • pause() => voidFunction to pause autoplay
  • isInView(index: number) => booleanWhether the item is in view
  • refresh() => voidFunction to re-compute the snap points and clamp the page

Data Attributes

Root
data-scope
carousel
data-part
root
data-orientation
The orientation of the carousel
ItemGroup
data-scope
carousel
data-part
item-group
data-orientation
The orientation of the item
data-dragging
Present when in the dragging state
Item
data-scope
carousel
data-part
item
data-index
The index of the item
data-inview
Present when in viewport
data-orientation
The orientation of the item
Control
data-scope
carousel
data-part
control
data-orientation
The orientation of the control
PrevTrigger
data-scope
carousel
data-part
prev-trigger
data-orientation
The orientation of the prevtrigger
NextTrigger
data-scope
carousel
data-part
next-trigger
data-orientation
The orientation of the nexttrigger
IndicatorGroup
data-scope
carousel
data-part
indicator-group
data-orientation
The orientation of the indicatorgroup
Indicator
data-scope
carousel
data-part
indicator
data-orientation
The orientation of the indicator
data-index
The index of the item
data-readonly
Present when read-only
data-current
Present when current
AutoplayTrigger
data-scope
carousel
data-part
autoplay-trigger
data-orientation
The orientation of the autoplaytrigger
data-pressed
Present when pressed

Edit this page on GitHub

Proudly made in🇳🇬by Segun Adebayo

Copyright © 2024
On this page