Edit Profile

Dark Mode

Copy config

Copy and paste the following code into your global.css file to apply the styles.

Carousel

Display and navigate through multiple content items.

✨ Features

  • Follows WAI-ARIA design pattern
  • Full keyboard navigation
  • Dynamic slide offsetting
  • Customizable alignment (start, center, end)
  • Pagination with bullet navigation
  • Navigate via Previous/Next buttons
  • Autoplay functionality
  • Rewind option
  • Support for multiple slides per view
  • Reactive slide updates
  • Initial slide selection
  • Carousels can be horizontal or vertical
  • Customizable accessible names
  • Supports carousels with or without scrollers
  • Optionally exposed as an accessible stepper
  • Supports custom animations
  • Integrates with progress bars and other components

HTML until users care

The Carousel is a common widget in landing pages and SSR-rendered environments (even above the fold). Unlike many carousel libraries that rely on heavy JavaScript hydration, our implementation is designed to be:

  • Environment agnostic (automatically SSR or CSR)
  • HTML-first
  • JavaScript-enhanced on interaction

The Carousel remains lightweight HTML until users interact with it through swiping, dragging, clicking, etc.

Hardware acceleration

Initially, this component was built with normal scroll behavior (including CSS Scroll Snapping), but our testing found it to be janky on mobile the moment a custom animation was added.

The Qwik UI Carousel uses CSS transforms and will-change for smooth, hardware-accelerated animations, optimizing performance across devices, especially on mobile.

Design Decisions

The Qwik UI Carousel is designed with the following intentions:

  • Consistency with Qwik UI's API design for ease of use
  • Modularity to support various use cases
  • Extendable with custom components

Alignment Options

Start Alignment

The default alignment is start. Slides will snap to the left edge of the carousel.

Center Alignment

Set the align prop to center to align slides to the center of the carousel.

End Alignment

Set the align prop to end to align slides to the right edge of the carousel.

Component State

Initial

To set an initial slide position, use the startIndex prop.

Reactive

Reactively control the selected slide index by using the bind:selectedIndex prop.

Multiple Slides

Set the slidesPerView prop for multiple slides.

Vertical

Qwik UI supports vertical carousels. Add the orientation prop with the value of vertical to the <Carousel.Root /> component.

Non-draggable

Opt-out of the draggable behavior by setting the draggable prop to false.

Different widths

By default, the slides will take up the full width of the carousel.

To change this, use the flex-basis CSS property on the <Carousel.Slide /> component.

Sensitivity

You can customize the sensitivity of the carousel dragging by passing an object with mouse and touch properties.

The default values are 1.5 for mouse and 1.25 for touch.

Move

You can customize the amount of slides to move when hitting the next or previous button by passing a number.

The default value is 1.

No Scroll

Qwik UI supports carousels without a scroller, which can be useful for conditional slide carousels.

Remove the <Carousel.Scroller /> component to remove the scroller.

Example Conditional Animation

.carousel-conditional {
  position: relative;
  height: 200px;
}
 
.carousel-conditional .carousel-slide {
  opacity: 0;
  transition: opacity 0.5s;
  /* NOT display block */
  display: revert;
  position: absolute;
  inset: 0;
}
 
.carousel-conditional .carousel-slide[data-active] {
  opacity: 1;
}

CSR

Both SSR and CSR are supported. In this example, we conditionally render the carousel based on an interaction.

Rewind

Rewind the carousel by setting the rewind prop to true.

Autoplay

To use autoplay, use the bind:autoplay prop.

isPlaying: false

Accessible name

By default, the carousel is automatically labeled with the aria-label attribute.

In the case that you want to add a custom accessible name, use the <Carousel.Title /> component.

To hide the title from screen readers, use the <VisuallyHidden /> component.

What if I want to autoplay on initial render?

Use a visible task to change the signal passed to bind:autoplay to true when the component is visible.

 {/* inside your component */}
  useVisibleTask$(() => {
    isAutoplaySig.value = true;
  })
 
  {/* the carousel */}
  <Carousel.Root bind:autoplay={isAutoplaySig}>

Custom scroll animations

To create a custom animation, use a CSS transition on the scroller with the transform property.

.carousel-animation {
  transition: 0.35s transform cubic-bezier(0.57, 0.16, 0.95, 0.67);
}

Configurations

Pagination

Use <Carousel.Pagination /> and <Carousel.Bullet /> components to add pagination.

Inspired by Adam Argyle's carousel examples, the carousel component allows the pagination to be extendable, while intending to be intuitive.

Stepper

The Carousel component also includes built-in accessibility support for steppers and setup wizards.

Steps can be disabled and enabled based on the index of the current slide or any other piece of state.

No Scroll

Similar to Carousel's, steppers can be used without a scroller.

Vertical

Vertical steppers can be created by changing the markup position of the stepper.

Presentational

Create non-interactive steppers by setting the as prop to div or span. Use Carousel.Next and Carousel.Previous components for navigation instead.

Progress

You can also control the progress of the carousel by using the bind:progress prop.

In the above example, we also use the headless progress component to show the progress of the carousel.

Initial Styles

@layer qwik-ui {
  [data-qui-carousel-viewport] {
    overflow: hidden;
  }
 
  [data-qui-carousel-scroller] {
    transform: var(--transform);
    will-change: transform;
    transition: 0.3s transform ease-out;
 
    display: flex;
    gap: var(--gap);
    flex-direction: var(--orientation);
 
    /* for initial slide position */
    scroll-snap-type: both mandatory;
    max-height: calc(var(--max-slide-height));
  }
 
  [data-qui-carousel-slide] {
    /* default, feel free to override */
    --total-gap-width: calc(var(--gap) * (var(--slides-per-view) - 1));
    --available-slide-width: calc(100% - var(--total-gap-width));
    --slide-width: calc(var(--available-slide-width) / var(--slides-per-view));
 
    flex-basis: var(--slide-width);
    flex-shrink: 0;
    position: relative;
  }
 
  @media (prefers-reduced-motion: reduce) {
    [data-qui-carousel-player] {
      display: none;
    }
  }
}

API

Carousel.Root

PropTypeDescription
gap
number

The gap between slides

slidesPerView
number

Number of slides to show at once

draggable
boolean

Whether the carousel is draggable

align
union

Alignment of slides within the viewport

rewind
boolean

Whether the carousel should rewind

'bind:selectedIndex'
Signal<number>

Bind the selected index to a signal

startIndex
number

change the initial index of the carousel on render

'bind:currSlideIndex'
Signal<number>

@deprecated Use bind:selectedIndex instead Bind the current slide index to a signal

'bind:autoplay'
Signal<boolean>

Whether the carousel should autoplay

'bind:progress'
Signal<number>

the current progress of the carousel

autoPlayIntervalMs
number

Time in milliseconds before the next slide plays during autoplay

_numSlides
number

@internal Total number of slides

_isTitle
boolean

@internal Whether this carousel has a title

sensitivity
object

The sensitivity of the carousel dragging