Carousel
Des slides à scroll-snap natif avec inertie au toucher, glisser à la souris, flèches du clavier, points, miniatures et une lecture automatique qui se met en pause au bon moment.
pnpm dlx shadcn@latest add https://hextaui.com/r/carousel.jsonAjoute le composant, les tokens de thème HextaUI et les composants HextaUI dont il dépend.
Ajoutez les tokens de thème à votre CSS global, si ce n’est pas déjà fait.
Installez les dépendances.
pnpm add @base-ui/react @tabler/icons-react class-variance-authority cnCopiez et collez le code suivant dans votre projet.
components/ui/carousel.tsx components/ui/button.tsx components/ui/number-flow.tsx lib/motion.ts Mettez à jour les chemins d’import selon la configuration de votre projet.
Les diapositives défilent nativement grâce au scroll snap CSS : l’inertie tactile et le défilement au pavé tactile se comportent comme sur la plateforme. La souris peut faire glisser, et les flèches avancent d’une diapositive à la fois.
API
Passez setApi pour obtenir l’API du carrousel, puis écoutez select pour afficher votre propre position. Next est désactivé sur la dernière diapositive mais garde le focus.
Plusieurs par vue
Les éléments définissent leur propre basis. Les gouttières viennent de la prop spacing, elles restent donc exactes quel que soit le basis.
Points et compteur
Le point actif s’étire pendant le défilement des diapositives et ses voisins lui font de la place. Le compteur ne fait tourner que le chiffre qui a changé.
Lecture automatique
autoplay est désactivé par défaut et le reste avec la réduction des animations. Il se met en pause au survol, au focus clavier, au toucher, au glissement, lorsque l’onglet est masqué ou que le carrousel sort de la vue, et le point actif se remplit pendant que le minuteur tourne.
Miniatures
<CarouselThumbnails /> suit le carrousel principal et défile pour garder la miniature active visible.
Vertical
orientation="vertical" nécessite une hauteur sur <CarouselContent />. Les boutons passent au-dessus et en dessous.
Contrôlé
Passez index et onIndexChange. Le balayage met à jour votre état et votre état fait défiler le carrousel.
Retour au début et index de départ
rewind renvoie Next de la dernière diapositive à la première. defaultIndex s’ouvre sur une diapositive sans animation de défilement.
Liens et contenu focusable
Faire glisser un lien avec la souris fait défiler sans l’ouvrir. Atteindre par tabulation une diapositive hors écran la fait défiler dans la vue.
Ajout et suppression de diapositives
Les points, le compteur et les boutons se mettent à jour à mesure que les diapositives apparaissent et disparaissent.
Imbriqué
Les flèches, le glissement et les points ne déplacent que le carrousel dans lequel vous vous trouvez.
Contenu long et diapositive unique
Le texte sans coupure passe à la ligne dans sa diapositive. Avec une seule diapositive, les points sont masqués et les boutons restent désactivés.
De droite à gauche
Les diapositives démarrent à droite, les flèches s’inversent, la flèche gauche fait avancer et les points se remplissent depuis la droite.
Les touches fonctionnent tant que le focus se trouve dans le carrousel, sauf dans les champs de texte et les carrousels imbriqués.
| Touche | Action |
|---|---|
| → | Diapositive suivante. Précédente dans les mises en page de droite à gauche. ↓ dans les carrousels verticaux. |
| ← | Diapositive précédente. Suivante dans les mises en page de droite à gauche. ↑ dans les carrousels verticaux. |
| Tab | Parcourt les boutons, le point actif et le contenu des diapositives, en faisant défiler dans la vue les diapositives hors écran. |
| EnterSpace | Active le bouton, le point ou la miniature ayant le focus. |
- La racine est une
regiondécrite comme un carrousel. Donnez-lui unaria-label. - Chaque élément est un
groupdécrit comme une diapositive et étiqueté avec sa position, par exemple « 3 of 5 ». - Une région live polie annonce la nouvelle diapositive après une navigation au clavier ou aux boutons, et reste silencieuse pendant la lecture automatique.
- Les points et les miniatures n’utilisent qu’un seul arrêt de tabulation, et le focus suit l’élément actif.
- Previous et Next restent focusables lorsqu’ils sont désactivés : le focus n’est donc jamais perdu à l’une ou l’autre extrémité.
| Prop | Type | Par défaut |
|---|---|---|
orientation | "horizontal" | "vertical" | "horizontal" |
spacingÉcart entre les diapositives. | "none" | "sm" | "default" | "lg" | "default" |
index | number | – |
defaultIndex | number | 0 |
onIndexChange | (index: number) => void | – |
rewindRevient de la dernière diapositive à la première. | boolean | false |
mouseDragPermet à la souris de faire glisser les diapositives. | boolean | true |
autoplayAvance automatiquement selon un minuteur. delay vaut 5000 ms par défaut, 1000 ms au minimum. | boolean | { delay?: number } | false |
setApi | (api: CarouselApi) => void | – |
render | ReactElement | (props, state) => ReactElement | <div> |
| Attribut | Description |
|---|---|
data-slot="carousel" | Ciblez la racine en CSS. |
data-orientation | L’orientation. |
--carousel-spacing | L’écart entre les diapositives, défini par spacing. |
| Prop | Type | Par défaut |
|---|---|---|
classNameAppliqué à la piste qui contient les diapositives. | string | – |
viewportClassNameAppliqué à la zone de défilement visible. | string | – |
| Attribut | Description |
|---|---|
data-slot="carousel-content" | La zone de défilement visible. |
data-slot="carousel-container" | La piste qu’elle contient. |
data-scrollable | Présent lorsqu’il y a plus d’une position. |
data-dragging | Présent pendant un glissement à la souris. |
| Prop | Type | Par défaut |
|---|---|---|
render | ReactElement | (props, state) => ReactElement | <div> |
| Attribut | Description |
|---|---|
data-slot="carousel-item" | Définissez basis-* pour en afficher plusieurs à la fois. |
Les deux rendent un <Button /> et acceptent ses props. Ils se placent en dehors du contenu : laissez donc de la place autour du carrousel.
| Prop | Type | Par défaut |
|---|---|---|
variant | ButtonProps["variant"] | "outline" |
size | ButtonProps["size"] | "icon-sm" |
childrenSuit l’orientation et la direction. | ReactNode | Arrow icon |
| Attribut | Description |
|---|---|
data-slot="carousel-previous" | Étiqueté « Previous slide ». |
data-slot="carousel-next" | Étiqueté « Next slide ». |
data-disabled | Présent à l’une ou l’autre extrémité. Le bouton reste focusable. |
| Prop | Type | Par défaut |
|---|---|---|
aria-label | string | "Choose slide" |
| Attribut | Description |
|---|---|
data-slot="carousel-dots" | Le groupe de points. Masqué lorsqu’il n’y a qu’une position. |
data-slot="carousel-dot" | Chaque point. Le point actif a aria-current. |
--dot-active | De 0 à 1, degré d’activité d’un point pendant le défilement. |
| Attribut | Description |
|---|---|
data-slot="carousel-counter" | Affiche la position actuelle sur le total avec un chiffre défilant. |
| Prop | Type | Par défaut |
|---|---|---|
variant | ButtonProps["variant"] | "ghost" |
size | ButtonProps["size"] | "icon-sm" |
| Attribut | Description |
|---|---|
data-slot="carousel-autoplay-toggle" | Étiqueté « Pause slideshow » ou « Play slideshow ». |
| Prop | Type | Par défaut |
|---|---|---|
aria-label | string | "Slides" |
| Attribut | Description |
|---|---|
data-slot="carousel-thumbnails" | La bande défilante. |
| Prop | Type | Par défaut |
|---|---|---|
indexLa diapositive qu’elle ouvre. Par défaut, sa position dans la bande. | number | – |
render | ReactElement | (props, state) => ReactElement | <button> |
| Attribut | Description |
|---|---|
data-slot="carousel-thumbnail" | Ciblez les miniatures en CSS. |
data-active | Présent tant que sa diapositive est visible. |
Retourné par setApi et useCarousel(). Passez jump: true pour se déplacer sans animation.
| Prop | Type | Par défaut |
|---|---|---|
scrollPrev | (jump?: boolean) => void | – |
scrollNext | (jump?: boolean) => void | – |
scrollToDéfile jusqu’à une position d’accroche. | (index: number, jump?: boolean) => void | – |
scrollToSlideDéfile jusqu’à la position qui affiche une diapositive. | (slideIndex: number, jump?: boolean) => void | – |
canScrollPrev | () => boolean | – |
canScrollNext | () => boolean | – |
selectedScrollSnap | () => number | – |
scrollSnapList | () => number[] | – |
slidesInView | () => number[] | – |
slideNodes | () => HTMLElement[] | – |
viewportNode | () => HTMLElement | null | – |
play | () => void | – |
stop | () => void | – |
isPlaying | () => boolean | – |
on / off | (event: "select" | "scroll" | "settle" | "reInit", listener) => CarouselApi | – |
À utiliser dans <Carousel /> pour construire vos propres contrôles. Retourne api, orientation, selectedIndex, snapCount, slideCount, slidesInView, canScrollPrev, canScrollNext, isPlaying ainsi que les méthodes de défilement et de lecture.
- ButtonDes boutons dans toutes les variantes et tailles, avec un flux de chargement, de succès et d’erreur intégré qui évite le spinner pour les requêtes rapides.
- Number flowDes nombres animés où seuls les chiffres modifiés tournent, avec n’importe quel format Intl et n’importe quelle locale.
- AccordionDes titres empilés qui révèlent chacun un panneau, avec un mouvement de hauteur réversible en cours de route et des panneaux qui restent consultables par la recherche une fois fermés.
- Aspect ratioUne boîte qui garde sa forme avant le chargement du média, scintille pendant le chargement, fait apparaître le média en fondu et bascule sur un repli en cas d’échec.
- CollapsibleUn panneau qui s’affiche et se masque avec un mouvement de hauteur réversible en cours de route, sans faire sauter la mise en page.
- ResizableDes panneaux que l’on peut écarter à la main, avec un séparateur discret qui s’éveille au survol, des tailles qui glissent à la réinitialisation ou au repli, et des mises en page persistantes.