Carousel
Display and navigate through multiple content items.
import { component$, useStyles$ } from '@builder.io/qwik';
import { Carousel } from '@qwik-ui/headless';
export default component$(() => {
useStyles$(styles);
const colors = ['red', 'green', 'blue', 'yellow', 'purple', 'orange', 'pink'];
return (
<Carousel.Root class="carousel-root" gap={30}>
<div class="carousel-buttons">
<Carousel.Previous>Prev</Carousel.Previous>
<Carousel.Next>Next</Carousel.Next>
</div>
<Carousel.Scroller class="carousel-scroller">
{colors.map((color) => (
<Carousel.Slide key={color} class="carousel-slide">
{color}
</Carousel.Slide>
))}
</Carousel.Scroller>
</Carousel.Root>
);
});
// internal
import styles from './carousel.css?inline';
✨ 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
Why use the Qwik UI Carousel
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.
import { component$, useStyles$ } from '@builder.io/qwik';
import { Carousel } from '@qwik-ui/headless';
export default component$(() => {
useStyles$(styles);
const colors = ['red', 'green', 'blue', 'yellow', 'purple', 'orange', 'pink'];
return (
<Carousel.Root class="carousel-root" gap={30}>
<div class="carousel-buttons">
<Carousel.Previous>Prev</Carousel.Previous>
<Carousel.Next>Next</Carousel.Next>
</div>
<Carousel.Scroller class="carousel-scroller">
{colors.map((color) => (
<Carousel.Slide
style={{ flexBasis: '300px' }}
key={color}
class="carousel-slide"
>
{color}
</Carousel.Slide>
))}
</Carousel.Scroller>
</Carousel.Root>
);
});
// internal
import styles from './carousel.css?inline';
Center Alignment
Set the align
prop to center
to align slides to the center of the carousel.
import { component$, useStyles$ } from '@builder.io/qwik';
import { Carousel } from '@qwik-ui/headless';
export default component$(() => {
useStyles$(styles);
const colors = ['red', 'green', 'blue', 'yellow', 'purple', 'orange', 'pink'];
return (
<Carousel.Root class="carousel-root" gap={30} align="center">
<div class="carousel-buttons">
<Carousel.Previous>Prev</Carousel.Previous>
<Carousel.Next>Next</Carousel.Next>
</div>
<Carousel.Scroller class="carousel-scroller">
{colors.map((color) => (
<Carousel.Slide
style={{ flexBasis: '300px' }}
key={color}
class="carousel-slide"
>
{color}
</Carousel.Slide>
))}
</Carousel.Scroller>
</Carousel.Root>
);
});
// internal
import styles from './carousel.css?inline';
End Alignment
Set the align
prop to end
to align slides to the right edge of the carousel.
import { component$, useStyles$ } from '@builder.io/qwik';
import { Carousel } from '@qwik-ui/headless';
export default component$(() => {
useStyles$(styles);
const colors = ['red', 'green', 'blue', 'yellow', 'purple', 'orange', 'pink'];
return (
<Carousel.Root class="carousel-root" gap={30} align="end">
<div class="carousel-buttons">
<Carousel.Previous>Prev</Carousel.Previous>
<Carousel.Next>Next</Carousel.Next>
</div>
<Carousel.Scroller class="carousel-scroller">
{colors.map((color) => (
<Carousel.Slide
style={{ flexBasis: '300px' }}
key={color}
class="carousel-slide"
>
{color}
</Carousel.Slide>
))}
</Carousel.Scroller>
</Carousel.Root>
);
});
// internal
import styles from './carousel.css?inline';
Component State
Initial
To set an initial slide position, use the startIndex
prop.
import { component$, useStyles$ } from '@builder.io/qwik';
import { Carousel } from '@qwik-ui/headless';
export default component$(() => {
useStyles$(styles);
const colors = ['red', 'green', 'blue', 'yellow', 'purple', 'orange', 'pink'];
return (
<Carousel.Root class="carousel-root" gap={30} startIndex={4}>
<div class="carousel-buttons">
<Carousel.Previous>Prev</Carousel.Previous>
<Carousel.Next>Next</Carousel.Next>
</div>
<Carousel.Scroller class="carousel-scroller">
{colors.map((color) => (
<Carousel.Slide key={color} class="carousel-slide">
{color}
</Carousel.Slide>
))}
</Carousel.Scroller>
</Carousel.Root>
);
});
// internal
import styles from './carousel.css?inline';
Reactive
Reactively control the selected slide index by using the bind:selectedIndex
prop.
import { component$, useSignal, useStyles$ } from '@builder.io/qwik';
import { Carousel } from '@qwik-ui/headless';
export default component$(() => {
useStyles$(styles);
const colors = ['red', 'green', 'blue', 'yellow', 'purple', 'orange', 'pink'];
const selectedIndex = useSignal<number>(2);
return (
<>
<Carousel.Root class="carousel-root" gap={30} bind:selectedIndex={selectedIndex}>
<div class="carousel-buttons">
<Carousel.Previous>Prev</Carousel.Previous>
<Carousel.Next>Next</Carousel.Next>
</div>
<Carousel.Scroller class="carousel-scroller">
{colors.map((color) => (
<Carousel.Slide key={color} class="carousel-slide">
{color}
</Carousel.Slide>
))}
</Carousel.Scroller>
</Carousel.Root>
<button>Selected Index: {selectedIndex.value}</button>
<button onClick$={() => (selectedIndex.value = 4)}>Change to index 4</button>
</>
);
});
// internal
import styles from './carousel.css?inline';
Multiple Slides
Set the slidesPerView
prop for multiple slides.
import { component$, useStyles$ } from '@builder.io/qwik';
import { Carousel } from '@qwik-ui/headless';
export default component$(() => {
useStyles$(styles);
const colors = ['red', 'green', 'blue', 'yellow', 'purple', 'orange', 'pink'];
return (
<Carousel.Root class="carousel-root" slidesPerView={3} gap={30}>
<div class="carousel-buttons">
<Carousel.Previous>Prev</Carousel.Previous>
<Carousel.Next>Next</Carousel.Next>
</div>
<Carousel.Scroller class="carousel-scroller">
{colors.map((color) => (
<Carousel.Slide key={color} class="carousel-slide">
{color}
</Carousel.Slide>
))}
</Carousel.Scroller>
<Carousel.Pagination class="carousel-pagination">
{colors.map((color, index) => (
<Carousel.Bullet class="carousel-pagination-bullet" key={color}>
{index + 1}
</Carousel.Bullet>
))}
</Carousel.Pagination>
</Carousel.Root>
);
});
// internal
import styles from './carousel.css?inline';
Vertical
Qwik UI supports vertical carousels. Add the orientation
prop with the value of vertical
to the <Carousel.Root />
component.
import { component$, useStyles$ } from '@builder.io/qwik';
import { Carousel } from '@qwik-ui/headless';
export default component$(() => {
useStyles$(styles);
const colors = ['red', 'green', 'blue', 'yellow', 'purple', 'orange', 'pink'];
return (
<Carousel.Root
class="carousel-root"
gap={30}
orientation="vertical"
maxSlideHeight={160}
>
<div class="carousel-buttons">
<Carousel.Previous>Prev</Carousel.Previous>
<Carousel.Next>Next</Carousel.Next>
</div>
<Carousel.Scroller class="carousel-scroller">
{colors.map((color) => (
<Carousel.Slide key={color} class="carousel-slide">
{color}
</Carousel.Slide>
))}
</Carousel.Scroller>
</Carousel.Root>
);
});
// internal
import styles from './carousel.css?inline';
Non-draggable
Opt-out of the draggable behavior by setting the draggable
prop to false
.
import { component$, useStyles$ } from '@builder.io/qwik';
import { Carousel } from '@qwik-ui/headless';
export default component$(() => {
useStyles$(styles);
const colors = ['red', 'green', 'blue', 'yellow', 'purple', 'orange', 'pink'];
return (
<Carousel.Root class="carousel-root" draggable={false}>
<div class="carousel-buttons">
<Carousel.Previous>Prev</Carousel.Previous>
<Carousel.Next>Next</Carousel.Next>
</div>
<Carousel.Scroller class="carousel-scroller">
{colors.map((color) => (
<Carousel.Slide key={color} class="carousel-slide">
{color}
</Carousel.Slide>
))}
</Carousel.Scroller>
</Carousel.Root>
);
});
// internal
import styles from './carousel.css?inline';
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.
import { component$, useStyles$ } from '@builder.io/qwik';
import { Carousel } from '@qwik-ui/headless';
export default component$(() => {
useStyles$(styles);
return (
<Carousel.Root class="carousel-root" gap={30}>
<div class="carousel-buttons">
<Carousel.Previous>Prev</Carousel.Previous>
<Carousel.Next>Next</Carousel.Next>
</div>
<Carousel.Scroller class="carousel-scroller">
<Carousel.Slide style={{ flexBasis: '200px' }} class="carousel-slide">
red
</Carousel.Slide>
<Carousel.Slide style={{ flexBasis: '400px' }} class="carousel-slide">
green
</Carousel.Slide>
<Carousel.Slide style={{ flexBasis: '300px' }} class="carousel-slide">
blue
</Carousel.Slide>
<Carousel.Slide style={{ flexBasis: '350px' }} class="carousel-slide">
yellow
</Carousel.Slide>
<Carousel.Slide style={{ flexBasis: '100px' }} class="carousel-slide">
purple
</Carousel.Slide>
</Carousel.Scroller>
</Carousel.Root>
);
});
// internal
import styles from './carousel.css?inline';
Sensitivity
You can customize the sensitivity of the carousel dragging by passing an object with mouse
and touch
properties.
import { component$, useStyles$ } from '@builder.io/qwik';
import { Carousel } from '@qwik-ui/headless';
export default component$(() => {
useStyles$(styles);
const colors = ['red', 'green', 'blue', 'yellow', 'purple', 'orange', 'pink'];
return (
<Carousel.Root
class="carousel-root"
gap={30}
sensitivity={{
mouse: 2.5,
touch: 2.25,
}}
>
<div class="carousel-buttons">
<Carousel.Previous>Prev</Carousel.Previous>
<Carousel.Next>Next</Carousel.Next>
</div>
<Carousel.Scroller class="carousel-scroller">
{colors.map((color) => (
<Carousel.Slide key={color} class="carousel-slide">
{color}
</Carousel.Slide>
))}
</Carousel.Scroller>
</Carousel.Root>
);
});
// internal
import styles from './carousel.css?inline';
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.
import { component$, useStyles$ } from '@builder.io/qwik';
import { Carousel } from '@qwik-ui/headless';
export default component$(() => {
useStyles$(styles);
const colors = ['red', 'green', 'blue', 'yellow', 'purple', 'orange', 'pink'];
useStyles$(`
.carousel-circle {
width: 20px;
height: 20px;
margin: 0 5px;
border-radius: 50%;
background-color: lightgray;
}
.carousel-circle[data-active] {
background-color: lightblue;
}
`);
return (
<>
<Carousel.Root class="carousel-root" gap={30} move={2} slidesPerView={2}>
<div class="carousel-buttons">
<Carousel.Previous>Prev</Carousel.Previous>
<Carousel.Next>Next</Carousel.Next>
</div>
<Carousel.Scroller class="carousel-scroller">
{colors.map((color) => (
<Carousel.Slide key={color} class="carousel-slide">
{color}
</Carousel.Slide>
))}
</Carousel.Scroller>
<Carousel.Pagination
style={{ display: 'flex', justifyContent: 'center', marginTop: '0.5rem' }}
>
{colors.map((_, index) => {
return (
<Carousel.Bullet key={index} class="carousel-circle"></Carousel.Bullet>
);
})}
</Carousel.Pagination>
</Carousel.Root>
</>
);
});
// internal
import styles from './carousel.css?inline';
The default value is 1
.
No Scroll
Qwik UI supports carousels without a scroller, which can be useful for conditional slide carousels.
import { component$, useStyles$ } from '@builder.io/qwik';
import { Carousel } from '@qwik-ui/headless';
export default component$(() => {
useStyles$(styles);
const colors = ['red', 'green', 'blue', 'yellow', 'purple', 'orange', 'pink'];
return (
<Carousel.Root class="carousel-root" gap={30}>
<div class="carousel-buttons">
<Carousel.Previous>Prev</Carousel.Previous>
<Carousel.Next>Next</Carousel.Next>
</div>
{colors.map((color) => (
<Carousel.Slide key={color} class="carousel-slide">
{color}
</Carousel.Slide>
))}
</Carousel.Root>
);
});
// internal
import styles from './carousel.css?inline';
Remove the <Carousel.Scroller />
component to remove the scroller.
Example Conditional Animation
import { component$, useStyles$ } from '@builder.io/qwik';
import { Carousel } from '@qwik-ui/headless';
export default component$(() => {
useStyles$(styles);
const colors = ['red', 'green', 'blue', 'yellow', 'purple', 'orange', 'pink'];
return (
<Carousel.Root class="carousel-root" gap={30}>
<div class="carousel-buttons">
<Carousel.Previous>Prev</Carousel.Previous>
<Carousel.Next>Next</Carousel.Next>
</div>
<div class="carousel-conditional">
{colors.map((color) => (
<Carousel.Slide key={color} class="carousel-slide">
{color}
</Carousel.Slide>
))}
</div>
</Carousel.Root>
);
});
// internal
import styles from './carousel.css?inline';
CSR
Both SSR and CSR are supported. In this example, we conditionally render the carousel based on an interaction.
import { component$, useSignal, useStyles$ } from '@builder.io/qwik';
import { Carousel } from '@qwik-ui/headless';
export default component$(() => {
useStyles$(styles);
const colors = ['red', 'green', 'blue', 'yellow', 'purple', 'orange', 'pink'];
const renderCarousel = useSignal(false);
return (
<>
<button onClick$={() => (renderCarousel.value = !renderCarousel.value)}>
Render Carousel
</button>
{renderCarousel.value && (
<Carousel.Root class="carousel-root">
<div class="carousel-buttons">
<Carousel.Previous>Prev</Carousel.Previous>
<Carousel.Next>Next</Carousel.Next>
</div>
<Carousel.Scroller class="carousel-scroller">
{colors.map((color) => (
<Carousel.Slide key={color} class="carousel-slide">
{color}
</Carousel.Slide>
))}
</Carousel.Scroller>
</Carousel.Root>
)}
</>
);
});
// internal
import styles from './carousel.css?inline';
Rewind
Rewind the carousel by setting the rewind
prop to true
.
import { component$, useStyles$ } from '@builder.io/qwik';
import { Carousel } from '@qwik-ui/headless';
export default component$(() => {
useStyles$(styles);
const colors = ['red', 'green', 'blue', 'yellow', 'purple', 'orange', 'pink'];
return (
<Carousel.Root class="carousel-root" gap={30} rewind>
<div class="carousel-buttons">
<Carousel.Previous>Prev</Carousel.Previous>
<Carousel.Next>Next</Carousel.Next>
</div>
<Carousel.Scroller class="carousel-scroller">
{colors.map((color) => (
<Carousel.Slide key={color} class="carousel-slide">
{color}
</Carousel.Slide>
))}
</Carousel.Scroller>
<Carousel.Pagination class="carousel-pagination">
{colors.map((color, index) => (
<Carousel.Bullet class="carousel-pagination-bullet" key={color}>
{index + 1}
</Carousel.Bullet>
))}
</Carousel.Pagination>
</Carousel.Root>
);
});
// internal
import styles from './carousel.css?inline';
Autoplay
To use autoplay, use the bind:autoplay
prop.
isPlaying: false
import { component$, useSignal, useStyles$ } from '@builder.io/qwik';
import { Carousel } from '@qwik-ui/headless';
import { LuPause, LuPlay } from '@qwikest/icons/lucide';
export default component$(() => {
useStyles$(styles);
const colors = ['red', 'green', 'blue', 'yellow', 'purple', 'orange', 'pink'];
const isPlaying = useSignal<boolean>(false);
return (
<>
<Carousel.Root
class="carousel-root"
gap={30}
autoPlayIntervalMs={3500}
bind:autoplay={isPlaying}
>
<div class="carousel-buttons">
<Carousel.Previous>Prev</Carousel.Previous>
<Carousel.Player>{isPlaying.value ? <LuPause /> : <LuPlay />}</Carousel.Player>
<Carousel.Next>Next</Carousel.Next>
</div>
<Carousel.Scroller class="carousel-scroller">
{colors.map((color, index) => (
<Carousel.Slide key={color} class="carousel-slide">
{color}
<div>{index === 1 && <button>I stop autoplay on focus!</button>}</div>
</Carousel.Slide>
))}
</Carousel.Scroller>
</Carousel.Root>
<p>isPlaying: {isPlaying.value.toString()}</p>
<button onClick$={() => (isPlaying.value = !isPlaying.value)}>
Toggle autoplay
</button>
</>
);
});
// internal
import styles from './carousel.css?inline';
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.
import { component$, useStyles$ } from '@builder.io/qwik';
import { Carousel } from '@qwik-ui/headless';
export default component$(() => {
useStyles$(styles);
const colors = ['red', 'green', 'blue', 'yellow', 'purple', 'orange', 'pink'];
return (
<Carousel.Root class="carousel-root" gap={30}>
<Carousel.Title>Favorite Colors</Carousel.Title>
<div class="carousel-buttons">
<Carousel.Previous>Prev</Carousel.Previous>
<Carousel.Next>Next</Carousel.Next>
</div>
<Carousel.Scroller class="carousel-scroller">
{colors.map((color) => (
<Carousel.Slide key={color} class="carousel-slide">
{color}
</Carousel.Slide>
))}
</Carousel.Scroller>
</Carousel.Root>
);
});
// internal
import styles from './carousel.css?inline';
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.
Custom scroll animations
To create a custom animation, use a CSS transition on the scroller with the transform
property.
import { component$, useStyles$ } from '@builder.io/qwik';
import { Carousel } from '@qwik-ui/headless';
export default component$(() => {
useStyles$(styles);
const colors = ['red', 'green', 'blue', 'yellow', 'purple', 'orange', 'pink'];
return (
<Carousel.Root class="carousel-root" gap={30}>
<div class="carousel-buttons">
<Carousel.Previous>Prev</Carousel.Previous>
<Carousel.Next>Next</Carousel.Next>
</div>
<Carousel.Scroller class="carousel-scroller carousel-animation">
{colors.map((color) => (
<Carousel.Slide key={color} class="carousel-slide">
{color}
</Carousel.Slide>
))}
</Carousel.Scroller>
</Carousel.Root>
);
});
// internal
import styles from './carousel.css?inline';
Configurations
Pagination
Use <Carousel.Pagination />
and <Carousel.Bullet />
components to add pagination.
import { component$, useStyles$ } from '@builder.io/qwik';
import { Carousel } from '@qwik-ui/headless';
export default component$(() => {
useStyles$(styles);
const colors = ['red', 'green', 'blue', 'yellow', 'purple', 'orange', 'pink'];
return (
<Carousel.Root class="carousel-root" gap={30}>
<div class="carousel-buttons">
<Carousel.Previous>Prev</Carousel.Previous>
<Carousel.Next>Next</Carousel.Next>
</div>
<Carousel.Scroller class="carousel-scroller">
{colors.map((color) => (
<Carousel.Slide key={color} class="carousel-slide">
{color}
</Carousel.Slide>
))}
</Carousel.Scroller>
<Carousel.Pagination class="carousel-pagination">
{colors.map((color, index) => (
<Carousel.Bullet class="carousel-pagination-bullet" key={color}>
{index + 1}
</Carousel.Bullet>
))}
</Carousel.Pagination>
</Carousel.Root>
);
});
// internal
import styles from './carousel.css?inline';
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.
import { component$, useStyles$ } from '@builder.io/qwik';
import { Carousel } from '@qwik-ui/headless';
export default component$(() => {
useStyles$(styles);
return (
<Carousel.Root class="carousel-root" gap={30}>
<Carousel.Stepper class="carousel-stepper">
{Array.from({ length: 3 }).map((_, index) => (
<Carousel.Step class="carousel-step">Header {index + 1}</Carousel.Step>
))}
</Carousel.Stepper>
<Carousel.Scroller class="carousel-scroller">
{Array.from({ length: 3 }).map((_, index) => (
<Carousel.Slide class="carousel-slide">Content {index + 1}</Carousel.Slide>
))}
</Carousel.Scroller>
</Carousel.Root>
);
});
// internal
import styles from './carousel.css?inline';
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.
import { component$, useStyles$ } from '@builder.io/qwik';
import { Carousel } from '@qwik-ui/headless';
export default component$(() => {
useStyles$(styles);
return (
<Carousel.Root class="carousel-root" gap={30}>
<Carousel.Stepper class="carousel-stepper">
{Array.from({ length: 3 }).map((_, index) => (
<Carousel.Step class="carousel-step">Header {index + 1}</Carousel.Step>
))}
</Carousel.Stepper>
{Array.from({ length: 3 }).map((_, index) => (
<Carousel.Slide class="carousel-slide">Content {index + 1}</Carousel.Slide>
))}
</Carousel.Root>
);
});
// internal
import styles from './carousel.css?inline';
Vertical
Vertical steppers can be created by changing the markup position of the stepper.
import { component$, useStyles$ } from '@builder.io/qwik';
import { Carousel } from '@qwik-ui/headless';
export default component$(() => {
useStyles$(styles);
const space = { marginBlock: '1rem' };
return (
<Carousel.Root class="carousel-root" gap={30}>
{/* example stepper css uses flex for horizontal examples */}
<Carousel.Stepper class="carousel-stepper" style={{ flexDirection: 'column' }}>
{Array.from({ length: 3 }).map((_, index) => (
<>
<Carousel.Step class="carousel-step">Header {index + 1}</Carousel.Step>
<Carousel.Slide style={space} class="carousel-slide">
Content {index + 1}
</Carousel.Slide>
</>
))}
</Carousel.Stepper>
</Carousel.Root>
);
});
// internal
import styles from './carousel.css?inline';
Presentational
Create non-interactive steppers by setting the as
prop to div
or span
. Use Carousel.Next
and Carousel.Previous
components for navigation instead.
import { component$, useStyles$ } from '@builder.io/qwik';
import { Carousel } from '@qwik-ui/headless';
export default component$(() => {
useStyles$(styles);
return (
<Carousel.Root class="carousel-root" gap={30}>
<Carousel.Stepper class="carousel-stepper">
{Array.from({ length: 3 }).map((_, index) => (
<Carousel.Step as="div" class="carousel-step">
Header {index + 1}
</Carousel.Step>
))}
</Carousel.Stepper>
<Carousel.Scroller class="carousel-scroller">
{Array.from({ length: 3 }).map((_, index) => (
<Carousel.Slide class="carousel-slide">Content {index + 1}</Carousel.Slide>
))}
</Carousel.Scroller>
</Carousel.Root>
);
});
// internal
import styles from './carousel.css?inline';
Progress
You can also control the progress of the carousel by using the bind:progress
prop.
import { component$, PropsOf, useSignal, useStyles$ } from '@builder.io/qwik';
import { Carousel, Progress } from '@qwik-ui/headless';
import styles from '../../progress/snippets/progress.css?inline';
export const CarouselProgress = component$((props: PropsOf<typeof Progress.Root>) => {
useStyles$(styles);
return (
<Progress.Root {...props} class="progress" style={{ marginBottom: '2rem' }}>
<Progress.Indicator class="progress-indicator" />
</Progress.Root>
);
});
export default component$(() => {
useStyles$(styles);
const progress = useSignal(0);
const colors = ['red', 'green', 'blue', 'yellow', 'purple', 'orange', 'pink'];
return (
<>
<CarouselProgress bind:value={progress} />
<Carousel.Root class="carousel-root" bind:progress={progress}>
<div class="carousel-buttons">
<Carousel.Previous>Prev</Carousel.Previous>
<Carousel.Next>Next</Carousel.Next>
</div>
{colors.map((color) => (
<Carousel.Slide key={color} class="carousel-slide">
{color}
</Carousel.Slide>
))}
</Carousel.Root>
</>
);
});
// internal
In the above example, we also use the headless progress component to show the progress of the carousel.
Initial Styles
API
Carousel.Root
Prop | Type | Description |
---|---|---|
gap | number | The gap between slides |
slidesPerView | number | Number of slides to show at once |
draggable | boolean | Whether the carousel is draggable |
align | union 'start' | 'center' | 'end' | 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 |