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


A slideshow component that cycles through elements.

Slide Image 0
Slide Image 1
Slide Image 2
Slide Image 3
Slide Image 4


  • Support for horizontal and vertical orientations.
  • Supports alignment of slides (start, center or end alignment).
  • Supports custom number of slides to show at a time.
  • Supports looping of slides.
  • Supports custom spacing between slides.


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.


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.


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" export function Carousel() { const [state, send] = useMachine(carousel.machine({ id: "1" })) const api = carousel.connect(state, send, normalizeProps) return ( <div {...api.rootProps}> <button {...api.prevTriggerProps}>Prev</button> <button {...api.nextTriggerProps}>Next</button> <div {...api.viewportProps}> <div {...api.itemGroupProps}> {, index) => ( <div {...api.getItemProps({ index })} key={index}> <img src={image} alt="" style={{ height: "300px", width: "100%", objectFit: "cover" }} /> </div> ))} </div> </div> </div> ) } const items = [ "", "", "", ]

Changing the orientation

By default, the carousel is assumed to be horizontal. To change the orientation to vertical, set the orientation property in the machine's context to vertical.

In this mode, the carousel will use the arrow up and down keys to increment/decrement its value.

Don't forget to change the styles of the vertical carousel by specifying its height.

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

Setting the initial slide

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

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

Setting the alignment of the slides

To set the alignment, set the align property in the machine's context to the start, center, or end value.

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

Setting the number of slides to show at a time

To customize number of slides to show, set the slidesPerView property in the machine's context to a number value or auto string.

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

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 amount of space 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 changes

When the carousel slide changes, the onIndexChange callback is invoked.

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

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="item"] { /* styles for the root part */ } [data-part="viewport"] { /* styles for the viewport part */ } [data-part="item-group"] { /* styles for the item-group part */ } [data-part="item"] { /* styles for the item 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 */ }

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:

  • orientation"horizontal" | "vertical"The orientation of the carousel.
  • align"start" | "center" | "end"The alignment of the slides in the carousel.
  • slidesPerViewnumber | "auto"The number of slides to show at a time.
  • loopbooleanWhether the carousel should loop around.
  • indexnumberThe current slide index.
  • spacingstringThe amount of space between slides.
  • onIndexChange(details: SlideChangeDetails) => voidFunction called when the slide changes.
  • idsPartial<{ root: string; viewport: string; slide(index: number): string; slideGroup: string; nextSlideTrigger: string; prevSlideTrigger: string; indicatorGroup: string; indicator(index: number): string; }>The ids of the elements in the carousel. Useful for composition.
  • 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.

Machine API

The carousel api exposes the following methods:

  • indexnumberThe current index of the carousel
  • scrollProgressnumberThe current scroll progress of the carousel
  • isAutoplaybooleanWhether the carousel is currently auto-playing
  • canScrollNextbooleanWhether the carousel is can scroll to the next slide
  • canScrollPrevbooleanWhether the carousel is can scroll to the previous slide
  • scrollTo(index: number, jump?: boolean) => voidFunction to scroll to a specific slide index
  • scrollToNext() => voidFunction to scroll to the next slide
  • scrollToPrevious() => voidFunction to scroll to the previous slide
  • getItemState(props: ItemProps) => ItemStateReturns the state of a specific slide
  • play() => voidFunction to start/resume autoplay
  • pause() => voidFunction to pause autoplay

Edit this page on GitHub

On this page