Carousel

A carousel with motion and swipe built using Stimulus.

Stimulus: shadcn--carousel
1
2
3
carousel/default
<%= render Shadcn::Carousel.new(class_name: "w-[280px]") do |carousel| %>
  <% carousel.with_slides do |slides| %>
    <% slides.with_item do %>
      <div class="flex aspect-square items-center justify-center rounded-md border bg-muted text-4xl font-semibold">
        1
      </div>
    <% end %>
    <% slides.with_item do %>
      <div class="flex aspect-square items-center justify-center rounded-md border bg-muted text-4xl font-semibold">
        2
      </div>
    <% end %>
    <% slides.with_item do %>
      <div class="flex aspect-square items-center justify-center rounded-md border bg-muted text-4xl font-semibold">
        3
      </div>
    <% end %>
  <% end %>
  <% carousel.with_previous %>
  <% carousel.with_next %>
<% end %>

Installation

Add the component to your project:

rails generate shadcn:add carousel

Usage

<%= render Shadcn::Carousel.new(class_name: "w-[280px]") do |carousel| %>
  <% carousel.with_slides do |slides| %>
    <% slides.with_item do %>
      <div class="flex aspect-square items-center justify-center rounded-md border bg-muted text-4xl font-semibold">
        1
      </div>
    <% end %>
    <% slides.with_item do %>
      <div class="flex aspect-square items-center justify-center rounded-md border bg-muted text-4xl font-semibold">
        2
      </div>
    <% end %>
    <% slides.with_item do %>
      <div class="flex aspect-square items-center justify-center rounded-md border bg-muted text-4xl font-semibold">
        3
      </div>
    <% end %>
  <% end %>
  <% carousel.with_previous %>
  <% carousel.with_next %>
<% end %>

Examples

With Images

Display images in a carousel.

Image 1
Image 2
Image 3
<div class="w-full max-w-lg mx-auto px-12">
  <%= render Shadcn::CarouselComponent.new do |carousel| %>
    <% carousel.with_slides do |slides| %>
      <% slides.with_item do %>
        <div class="aspect-video bg-gradient-to-br from-blue-500 to-purple-600 rounded-lg flex items-center justify-center text-white text-xl font-bold">
          Image 1
        </div>
      <% end %>
      <% slides.with_item do %>
        <div class="aspect-video bg-gradient-to-br from-green-500 to-teal-600 rounded-lg flex items-center justify-center text-white text-xl font-bold">
          Image 2
        </div>
      <% end %>
      <% slides.with_item do %>
        <div class="aspect-video bg-gradient-to-br from-orange-500 to-red-600 rounded-lg flex items-center justify-center text-white text-xl font-bold">
          Image 3
        </div>
      <% end %>
    <% end %>
    <% carousel.with_previous %>
    <% carousel.with_next %>
  <% end %>
</div>

Custom Item Sizes

Use the basis prop on items to show multiple slides at once.

1
2
3
4
5
6
7
8
<div class="w-full max-w-xl mx-auto px-12">
  <%= render Shadcn::CarouselComponent.new do |carousel| %>
    <% carousel.with_slides do |slides| %>
      <% 8.times do |i| %>
        <% slides.with_item(basis: "basis-1/3") do %>
          <div class="flex aspect-square items-center justify-center p-4 bg-muted rounded-lg">
            <span class="text-2xl font-semibold"><%= i + 1 %></span>
          </div>
        <% end %>
      <% end %>
    <% end %>
    <% carousel.with_previous %>
    <% carousel.with_next %>
  <% end %>
</div>

Vertical Orientation

Use orientation: :vertical for vertical carousels.

1
2
3
4
5
<div class="w-full max-w-xs mx-auto pt-12 pb-12">
  <%= render Shadcn::CarouselComponent.new(orientation: :vertical) do |carousel| %>
    <% carousel.with_slides(class_name: "max-h-[200px]") do |slides| %>
      <% 5.times do |i| %>
        <% slides.with_item do %>
          <div class="flex h-[80px] items-center justify-center bg-muted rounded-lg">
            <span class="text-2xl font-semibold"><%= i + 1 %></span>
          </div>
        <% end %>
      <% end %>
    <% end %>
    <% carousel.with_previous %>
    <% carousel.with_next %>
  <% end %>
</div>

Infinite Loop

Enable infinite looping with the loop option.

1
2
3
4
5
<div class="w-full max-w-md mx-auto px-12">
  <%= render Shadcn::CarouselComponent.new(loop: true) do |carousel| %>
    <% carousel.with_slides do |slides| %>
      <% 5.times do |i| %>
        <% slides.with_item do %>
          <div class="flex aspect-square items-center justify-center p-6 bg-muted rounded-lg">
            <span class="text-4xl font-semibold"><%= i + 1 %></span>
          </div>
        <% end %>
      <% end %>
    <% end %>
    <% carousel.with_previous %>
    <% carousel.with_next %>
  <% end %>
</div>

Autoplay

Automatically advance slides with the autoplay option.

1
2
3
4
5
<div class="w-full max-w-md mx-auto px-12">
  <%= render Shadcn::CarouselComponent.new(autoplay: true, autoplay_interval: 3000, loop: true) do |carousel| %>
    <% carousel.with_slides do |slides| %>
      <% 5.times do |i| %>
        <% slides.with_item do %>
          <div class="flex aspect-square items-center justify-center p-6 bg-primary text-primary-foreground rounded-lg">
            <span class="text-4xl font-semibold"><%= i + 1 %></span>
          </div>
        <% end %>
      <% end %>
    <% end %>
    <% carousel.with_previous %>
    <% carousel.with_next %>
  <% end %>
</div>

With Card Content

Carousel items can contain any content, including cards.

Getting Started

Learn the basics of the framework

Content goes here

Components

Explore our component library

Content goes here

Theming

Customize colors and styles

Content goes here
<% cards = [
  { title: "Getting Started", description: "Learn the basics of the framework" },
  { title: "Components", description: "Explore our component library" },
  { title: "Theming", description: "Customize colors and styles" }
] %>

<div class="w-full max-w-lg mx-auto px-12">
  <%= render Shadcn::Carousel.new do |carousel| %>
    <% carousel.with_slides do |slides| %>
      <% cards.each do |card| %>
        <% slides.with_item do %>
          <%= render Shadcn::Card.new do |c| %>
            <% c.with_header do |header| %>
              <% header.with_title { card[:title] } %>
              <% header.with_description { card[:description] } %>
            <% end %>
            <% c.with_content do %>
              <div class="h-24 bg-muted rounded flex items-center justify-center">
                Content goes here
              </div>
            <% end %>
          <% end %>
        <% end %>
      <% end %>
    <% end %>
    <% carousel.with_previous %>
    <% carousel.with_next %>
  <% end %>
</div>

API Reference

API Reference

Prop Type Default Description
orientation Symbol :horizontal Direction of carousel (:horizontal, :vertical)
loop Boolean false Whether to loop infinitely
autoplay Boolean false Whether to auto-advance slides
autoplay_interval Integer 4000 Milliseconds between auto-advance
align Symbol :start Item alignment (:start, :center, :end)
class_name String nil Additional CSS classes

Slots

Slot Description
with_slides Container for carousel items
slides.with_item(basis:) Individual carousel item. Use basis for custom widths
with_previous Previous slide button
with_next Next slide button

Stimulus Controller

This component requires JavaScript. The Stimulus controller shadcn--carousel provides interactivity.

Manages carousel navigation, autoplay, keyboard navigation, and touch/swipe gestures.

Installation

Add to your config/importmap.rb:

pin "shadcn", to: "index.esm.js"

Then in your app/javascript/controllers/index.js:

import { Application } from "@hotwired/stimulus"
import { registerShadcnControllers } from "shadcn"

const application = Application.start()
registerShadcnControllers(application)

Or import just this controller:

import CarouselController from "shadcn-rails-stimulus/controllers/carousel_controller"

application.register("shadcn--carousel", CarouselController)

Values

Name Type Default Description
orientation String "horizontal" Direction (horizontal or vertical)
loop Boolean false Whether to loop infinitely
autoplay Boolean false Whether to auto-advance
autoplayInterval Number 4000 Milliseconds between auto-advance
align String "start" Item alignment (start, center, end)
selectedIndex Number 0 Currently selected slide index

Actions

Action Description
previous Go to the previous slide
next Go to the next slide
goToSlide Go to a specific slide by index (use data-index)

TypeScript

Type definitions are included. Import types as needed:

import type { CarouselController } from "shadcn-rails-stimulus"

Accessibility

  • Uses role="region" with aria-roledescription="carousel"
  • Each slide has role="group" with aria-roledescription="slide"
  • Non-visible slides are marked with aria-hidden="true" and inert
  • Keyboard navigation: Arrow Left/Right (horizontal) or Up/Down (vertical)
  • Touch/swipe support on mobile devices
  • Autoplay pauses on hover and touch interaction