WARNING: This component is in
Draft
status. This means that it is still in development and may have bugs or missing features. It is not intended to be used in production. You may use it for testing purposes.Carousel
A control that displays a set of content in a scrolling container.
0
1
2
3
4
5
6
7
8
9
import { $, component$, useSignal, useStyles$ } from '@builder.io/qwik';
import {
Carousel,
CarouselNext,
CarouselPrev,
CarouselSlide,
CarouselView,
CarouselContainer,
CarouselPagination,
} from '@qwik-ui/headless';
import carouselStyles from './carousel.css?inline';
export default component$(() => {
/* TODO: document this to always have initial state to null.
Use defaultSlide instead for setting a slide on page load */
const currentIndexSig = useSignal<number>(0);
useStyles$(carouselStyles);
const slideImageMetadata = [
{
id: '10',
author: 'Paul Jarvis',
width: 2500,
height: 1667,
url: 'https://unsplash.com/photos/6J--NXulQCs',
download_url: 'https://picsum.photos/id/10/2500/1667',
},
{
id: '11',
author: 'Paul Jarvis',
width: 2500,
height: 1667,
url: 'https://unsplash.com/photos/Cm7oKel-X2Q',
download_url: 'https://picsum.photos/id/11/2500/1667',
},
{
id: '12',
author: 'Paul Jarvis',
width: 2500,
height: 1667,
url: 'https://unsplash.com/photos/I_9ILwtsl_k',
download_url: 'https://picsum.photos/id/12/2500/1667',
},
{
id: '13',
author: 'Paul Jarvis',
width: 2500,
height: 1667,
url: 'https://unsplash.com/photos/3MtiSMdnoCo',
download_url: 'https://picsum.photos/id/13/2500/1667',
},
{
id: '14',
author: 'Paul Jarvis',
width: 2500,
height: 1667,
url: 'https://unsplash.com/photos/IQ1kOQTJrOQ',
download_url: 'https://picsum.photos/id/14/2500/1667',
},
{
id: '15',
author: 'Paul Jarvis',
width: 2500,
height: 1667,
url: 'https://unsplash.com/photos/NYDo21ssGao',
download_url: 'https://picsum.photos/id/15/2500/1667',
},
{
id: '16',
author: 'Paul Jarvis',
width: 2500,
height: 1667,
url: 'https://unsplash.com/photos/gkT4FfgHO5o',
download_url: 'https://picsum.photos/id/16/2500/1667',
},
{
id: '17',
author: 'Paul Jarvis',
width: 2500,
height: 1667,
url: 'https://unsplash.com/photos/Ven2CV8IJ5A',
download_url: 'https://picsum.photos/id/17/2500/1667',
},
{
id: '18',
author: 'Paul Jarvis',
width: 2500,
height: 1667,
url: 'https://unsplash.com/photos/Ps2n0rShqaM',
download_url: 'https://picsum.photos/id/18/2500/1667',
},
{
id: '19',
author: 'Paul Jarvis',
width: 2500,
height: 1667,
url: 'https://unsplash.com/photos/P7Lh0usGcuk',
download_url: 'https://picsum.photos/id/19/2500/1667',
},
];
return (
<Carousel
bind:currSlideIndex={currentIndexSig}
spaceBetweenSlides={30}
class="carousel"
>
<div class="carousel-buttons">
<CarouselPrev class="prev-button">Prev</CarouselPrev>
<CarouselNext class="next-button">Next</CarouselNext>
</div>
<CarouselView>
<CarouselContainer class="carousel-container">
{slideImageMetadata.map((data) => (
<CarouselSlide key={data.id} class="carousel-slide">
<img
class="carousel-img"
width="640"
height="320"
src={`https://picsum.photos/id/${data.id}/640/320`}
alt={data.author}
/>
</CarouselSlide>
))}
</CarouselContainer>
</CarouselView>
<div>
<CarouselPagination
class="carousel-pagination"
renderBullet$={$((i: number) => {
return (
<div
class={`carousel-pagination-bullet ${
currentIndexSig.value === i ? 'pagination-underline' : ''
}`}
onClick$={() => (currentIndexSig.value = i)}
>
{i}
</div>
);
})}
/>
</div>
</Carousel>
);
});
✨ Features
- Mobile Swiping
- Draggable
- Dynamic Slide Offsetting
- Transition Duration Control
- Pagination
- Navigate via Prev/Next buttons
- Tests
- Documentation
- Fix for the "snapping" behavior when going pass the last slide
- A refactor of the API (for example, conventions like the select)
- Remove additional styles to the headless component
Roadmap
What's different to Swiper JS or Embla Carousel?
This component initially started as a wrapper around Swiper JS, but has since been rewritten natively in Qwik! It's a automatically optimized and a lightweight solution.
This component also intends to be more accessible with a powerful API.
Why is there styles currently directly in headless?
The component itself does include headless logic, but also uses the flex layout algorithm, and is in sort of a "gray" zone betweeen styled / unstyled.
In the future, we would prefer a polished headless component (devoid of styles for most part).