Carousel
A slideshow component that cycles through elements.
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-partattribute to help identify them in the DOM.
Examples
Learn how to use the Carousel component in your project. Let's take a look at the most basic
example:
import { Carousel } from '@ark-ui/react'
export const Basic = () => {
  const images = [
    'https://tinyurl.com/5b6ka8jd',
    'https://tinyurl.com/7rmccdn5',
    'https://tinyurl.com/59jxz9uu',
  ]
  return (
    <Carousel.Root>
      <Carousel.Control>
        <Carousel.PrevTrigger>Previous</Carousel.PrevTrigger>
        <Carousel.NextTrigger>Next</Carousel.NextTrigger>
      </Carousel.Control>
      <Carousel.IndicatorGroup>
        {images.map((_, index) => (
          <Carousel.Indicator key={index} index={index}>
            {index + 1}
          </Carousel.Indicator>
        ))}
      </Carousel.IndicatorGroup>
      <Carousel.Viewport>
        <Carousel.ItemGroup>
          {images.map((image, index) => (
            <Carousel.Item key={index} index={index}>
              <img src={image} alt={`Slide ${index}`} />
            </Carousel.Item>
          ))}
        </Carousel.ItemGroup>
      </Carousel.Viewport>
    </Carousel.Root>
  )
}
import { Index } from 'solid-js'
import { Carousel } from '@ark-ui/solid'
export const Basic = () => {
  const images = [
    'https://tinyurl.com/5b6ka8jd',
    'https://tinyurl.com/7rmccdn5',
    'https://tinyurl.com/59jxz9uu',
    'https://tinyurl.com/6jurv23t',
    'https://tinyurl.com/yp4rfum7',
  ]
  return (
    <Carousel.Root>
      <Carousel.Control>
        <Carousel.PrevTrigger>Previous</Carousel.PrevTrigger>
        <Carousel.NextTrigger>Next</Carousel.NextTrigger>
      </Carousel.Control>
      <Carousel.IndicatorGroup>
        <Index each={images}>
          {(_, index) => <Carousel.Indicator index={index}>{index + 1}</Carousel.Indicator>}
        </Index>
      </Carousel.IndicatorGroup>
      <Carousel.Viewport>
        <Carousel.ItemGroup>
          <Index each={images}>
            {(image, index) => (
              <Carousel.Item index={index}>
                <img src={image()} alt={`Slide ${index}`} />
              </Carousel.Item>
            )}
          </Index>
        </Carousel.ItemGroup>
      </Carousel.Viewport>
    </Carousel.Root>
  )
}
<script setup lang="ts">
import { Carousel } from '@ark-ui/vue'
const images = [
  'https://tinyurl.com/5b6ka8jd',
  'https://tinyurl.com/7rmccdn5',
  'https://tinyurl.com/59jxz9uu',
  'https://tinyurl.com/6jurv23t',
  'https://tinyurl.com/yp4rfum7',
]
</script>
<template>
  <Carousel.Root>
    <Carousel.Control>
      <Carousel.PrevTrigger>Previous</Carousel.PrevTrigger>
      <Carousel.NextTrigger>Next</Carousel.NextTrigger>
    </Carousel.Control>
    <Carousel.IndicatorGroup>
      <Carousel.Indicator v-for="(_, idx) in images" :key="idx" :index="idx">
        {{ idx + 1 }}
      </Carousel.Indicator>
    </Carousel.IndicatorGroup>
    <Carousel.Viewport>
      <Carousel.ItemGroup>
        <Carousel.Item v-for="(image, idx) in images" :key="idx" :index="idx">
          <img
            :src="image"
            alt=""
            :style="{ height: '300px', width: '100%', objectFit: 'cover' }"
          />
        </Carousel.Item>
      </Carousel.ItemGroup>
    </Carousel.Viewport>
  </Carousel.Root>
</template>
Controlled Carousel
To create a controlled Carousel component, you can manage the state of the carousel using the
index prop and update it when the onIndexChange event handler is called:
import { useState } from 'react'
import { Carousel } from '@ark-ui/react'
export const Controlled = () => {
  const [currentIndex, setCurrentIndex] = useState(0)
  const images = [
    'https://tinyurl.com/5b6ka8jd',
    'https://tinyurl.com/7rmccdn5',
    'https://tinyurl.com/59jxz9uu',
  ]
  return (
    <Carousel.Root index={currentIndex} onIndexChange={(details) => setCurrentIndex(details.index)}>
      <Carousel.Control>
        <Carousel.PrevTrigger>Previous</Carousel.PrevTrigger>
        <Carousel.NextTrigger>Next</Carousel.NextTrigger>
      </Carousel.Control>
      <Carousel.IndicatorGroup>
        {images.map((_, index) => (
          <Carousel.Indicator key={index} index={index}>
            {index + 1}
          </Carousel.Indicator>
        ))}
      </Carousel.IndicatorGroup>
      <Carousel.Viewport>
        <Carousel.ItemGroup>
          {images.map((image, index) => (
            <Carousel.Item key={index} index={index}>
              <img src={image} alt={`Slide ${index}`} />
            </Carousel.Item>
          ))}
        </Carousel.ItemGroup>
      </Carousel.Viewport>
    </Carousel.Root>
  )
}
import { Index, createSignal } from 'solid-js'
import { Carousel } from '@ark-ui/solid'
export const Controlled = () => {
  const [currentIndex, setCurrentIndex] = createSignal(0)
  const images = [
    'https://tinyurl.com/5b6ka8jd',
    'https://tinyurl.com/7rmccdn5',
    'https://tinyurl.com/59jxz9uu',
    'https://tinyurl.com/6jurv23t',
    'https://tinyurl.com/yp4rfum7',
  ]
  return (
    <>
      <Carousel.Root
        index={currentIndex()}
        onIndexChange={(details) => setCurrentIndex(details.index)}
      >
        <Carousel.Control>
          <Carousel.PrevTrigger>Previous</Carousel.PrevTrigger>
          <Carousel.NextTrigger>Next</Carousel.NextTrigger>
        </Carousel.Control>
        <Carousel.Viewport>
          <Carousel.ItemGroup>
            <Index each={images}>
              {(image, index) => (
                <Carousel.Item index={index}>
                  <img src={image()} alt={`Slide ${index}`} />
                </Carousel.Item>
              )}
            </Index>
          </Carousel.ItemGroup>
        </Carousel.Viewport>
      </Carousel.Root>
    </>
  )
}
<script setup lang="ts">
import { ref } from 'vue'
import { Carousel } from '@ark-ui/vue'
const images = [
  'https://tinyurl.com/5b6ka8jd',
  'https://tinyurl.com/7rmccdn5',
  'https://tinyurl.com/59jxz9uu',
  'https://tinyurl.com/6jurv23t',
  'https://tinyurl.com/yp4rfum7',
]
const index = ref(0)
</script>
<template>
  <Carousel.Root v-model:index="index">
    <Carousel.Control>
      <Carousel.PrevTrigger>Previous</Carousel.PrevTrigger>
      <Carousel.NextTrigger>Next</Carousel.NextTrigger>
    </Carousel.Control>
    <Carousel.IndicatorGroup>
      <Carousel.Indicator v-for="(_, idx) in images" :key="idx" :index="idx">
        {{ idx + 1 }}
      </Carousel.Indicator>
    </Carousel.IndicatorGroup>
    <Carousel.Viewport>
      <Carousel.ItemGroup>
        <Carousel.Item v-for="(image, idx) in images" :key="idx" :index="idx">
          <img
            :src="image"
            alt=""
            :style="{ height: '300px', width: '100%', objectFit: 'cover' }"
          />
        </Carousel.Item>
      </Carousel.ItemGroup>
    </Carousel.Viewport>
  </Carousel.Root>
</template>
Customizing the Carousel
You can customize the Carousel component by setting various props. Here's an example of a customized Carousel:
import { Carousel } from '@ark-ui/react'
export const Customized = () => {
  const images = [
    'https://tinyurl.com/5b6ka8jd',
    'https://tinyurl.com/7rmccdn5',
    'https://tinyurl.com/59jxz9uu',
  ]
  return (
    <Carousel.Root
      align="center"
      loop={true}
      slidesPerView={2}
      spacing="16px"
      orientation="horizontal"
    >
      <Carousel.Control>
        <Carousel.PrevTrigger>Previous</Carousel.PrevTrigger>
        <Carousel.NextTrigger>Next</Carousel.NextTrigger>
      </Carousel.Control>
      <Carousel.IndicatorGroup>
        {images.map((_, index) => (
          <Carousel.Indicator key={index} index={index}>
            {index + 1}
          </Carousel.Indicator>
        ))}
      </Carousel.IndicatorGroup>
      <Carousel.Viewport>
        <Carousel.ItemGroup>
          {images.map((image, index) => (
            <Carousel.Item key={index} index={index}>
              <img src={image} alt={`Slide ${index}`} />
            </Carousel.Item>
          ))}
        </Carousel.ItemGroup>
      </Carousel.Viewport>
    </Carousel.Root>
  )
}
import { Index } from 'solid-js'
import { Carousel } from '@ark-ui/solid'
export const Customized = () => {
  const images = [
    'https://tinyurl.com/5b6ka8jd',
    'https://tinyurl.com/7rmccdn5',
    'https://tinyurl.com/59jxz9uu',
  ]
  return (
    <Carousel.Root
      align="center"
      loop={true}
      slidesPerView={2}
      spacing="16px"
      orientation="horizontal"
    >
      <Carousel.Control>
        <Carousel.PrevTrigger>Previous</Carousel.PrevTrigger>
        <Carousel.NextTrigger>Next</Carousel.NextTrigger>
      </Carousel.Control>
      <Carousel.IndicatorGroup>
        <Index each={images}>
          {(_, index) => <Carousel.Indicator index={index}>{index + 1}</Carousel.Indicator>}
        </Index>
      </Carousel.IndicatorGroup>
      <Carousel.Viewport>
        <Carousel.ItemGroup>
          <Index each={images}>
            {(image, index) => (
              <Carousel.Item index={index}>
                <img src={image()} alt={`Slide ${index}`} />
              </Carousel.Item>
            )}
          </Index>
        </Carousel.ItemGroup>
      </Carousel.Viewport>
    </Carousel.Root>
  )
}
<script setup lang="ts">
import { Carousel } from '@ark-ui/vue'
const images = [
  'https://tinyurl.com/5b6ka8jd',
  'https://tinyurl.com/7rmccdn5',
  'https://tinyurl.com/59jxz9uu',
  'https://tinyurl.com/6jurv23t',
  'https://tinyurl.com/yp4rfum7',
]
</script>
<template>
  <Carousel.Root
    :align="'center'"
    loop
    :slides-per-view="2"
    spacing="16px"
    orientation="horizontal"
  >
    <Carousel.Control>
      <Carousel.PrevTrigger>Previous</Carousel.PrevTrigger>
      <Carousel.NextTrigger>Next</Carousel.NextTrigger>
    </Carousel.Control>
    <Carousel.IndicatorGroup>
      <Carousel.Indicator v-for="(_, idx) in images" :key="idx" :index="idx">
        {{ idx + 1 }}
      </Carousel.Indicator>
    </Carousel.IndicatorGroup>
    <Carousel.Viewport>
      <Carousel.ItemGroup>
        <Carousel.Item v-for="(image, idx) in images" :key="idx" :index="idx">
          <img
            :src="image"
            alt=""
            :style="{ height: '300px', width: '100%', objectFit: 'cover' }"
          />
        </Carousel.Item>
      </Carousel.ItemGroup>
    </Carousel.Viewport>
  </Carousel.Root>
</template>
API Reference
Root
| Prop | Default | Type | 
|---|---|---|
| align | 'start' | 'center' | 'end' | 'start'The alignment of the slides in the carousel. | 
| asChild | booleanUse the provided child element as the default rendered element, combining their props and behavior.For more details, read our Composition guide. | |
| defaultIndex | numberThe initial index of the carousel when it is first rendered. Use this when you do not need to control the state of the carousel. | |
| ids | Partial<{
  root: string
  viewport: 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. | |
| index | numberThe current slide index. | |
| loop | false | booleanWhether the carousel should loop around. | 
| onIndexChange | (details: SlideChangeDetails) => voidFunction called when the slide changes. | |
| orientation | 'horizontal' | 'horizontal' | 'vertical'The orientation of the carousel. | 
| slidesPerView | 1 | number | 'auto'The number of slides to show at a time. | 
| spacing | '0px' | stringThe amount of space between slides. | 
| Data Attribute | Value | 
|---|---|
| [data-scope] | carousel | 
| [data-part] | root | 
| [data-orientation] | The orientation of the carousel | 
Control
| Prop | Default | Type | 
|---|---|---|
| asChild | booleanUse the provided child element as the default rendered element, combining their props and behavior.For more details, read our Composition guide. | 
IndicatorGroup
| Prop | Default | Type | 
|---|---|---|
| asChild | booleanUse the provided child element as the default rendered element, combining their props and behavior.For more details, read our Composition guide. | 
| Data Attribute | Value | 
|---|---|
| [data-scope] | carousel | 
| [data-part] | indicator-group | 
| [data-orientation] | The orientation of the indicatorgroup | 
Indicator
| Prop | Default | Type | 
|---|---|---|
| index | number | |
| asChild | booleanUse the provided child element as the default rendered element, combining their props and behavior.For more details, read our Composition guide. | |
| readOnly | boolean | 
| Data Attribute | Value | 
|---|---|
| [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 | 
ItemGroup
| Prop | Default | Type | 
|---|---|---|
| asChild | booleanUse the provided child element as the default rendered element, combining their props and behavior.For more details, read our Composition guide. | 
| Data Attribute | Value | 
|---|---|
| [data-scope] | carousel | 
| [data-part] | item-group | 
| [data-orientation] | The orientation of the item | 
Item
| Prop | Default | Type | 
|---|---|---|
| index | numberThe index of the item. | |
| asChild | booleanUse the provided child element as the default rendered element, combining their props and behavior.For more details, read our Composition guide. | 
| Data Attribute | Value | 
|---|---|
| [data-scope] | carousel | 
| [data-part] | item | 
| [data-current] | Present when current | 
| [data-inview] | Present when in viewport | 
| [data-orientation] | The orientation of the item | 
NextTrigger
| Prop | Default | Type | 
|---|---|---|
| asChild | booleanUse the provided child element as the default rendered element, combining their props and behavior.For more details, read our Composition guide. | 
| Data Attribute | Value | 
|---|---|
| [data-scope] | carousel | 
| [data-part] | next-trigger | 
| [data-orientation] | The orientation of the nexttrigger | 
PrevTrigger
| Prop | Default | Type | 
|---|---|---|
| asChild | booleanUse the provided child element as the default rendered element, combining their props and behavior.For more details, read our Composition guide. | 
| Data Attribute | Value | 
|---|---|
| [data-scope] | carousel | 
| [data-part] | prev-trigger | 
| [data-orientation] | The orientation of the prevtrigger | 
RootProvider
| Prop | Default | Type | 
|---|---|---|
| value | UseCarouselReturn | |
| asChild | booleanUse the provided child element as the default rendered element, combining their props and behavior.For more details, read our Composition guide. | 
Viewport
| Prop | Default | Type | 
|---|---|---|
| asChild | booleanUse the provided child element as the default rendered element, combining their props and behavior.For more details, read our Composition guide. | 
| Data Attribute | Value | 
|---|---|
| [data-scope] | carousel | 
| [data-part] | viewport | 
| [data-orientation] | The orientation of the viewport | 
Accessibility
Complies with the Carousel WAI-ARIA design pattern.