Carousel
an accessible carousel component that leverages native CSS Scroll Snap for smooth, performant scrolling between slides.
Features
Install
Install the component from your command line.
Anatomy
Import all parts and piece them together.
<script setup lang="ts">import * as carousel from '@destyler/carousel'import { normalizeProps, useMachine } from '@destyler/vue'import { computed, useId } from 'vue'
const [state, send] = useMachine( carousel.machine({ id: useId(), }))
const api = computed(() => carousel.connect(state.value, send, normalizeProps),)</script>
<template> <div v-bind="api.getRootProps()"> <div v-bind="api.getItemGroupProps()"> <div v-bind="api.getItemProps({ index:0 })"> <img> </div> </div>
<div v-bind="api.getControlProps()"> <button v-bind="api.getPrevTriggerProps()"/> <div v-bind="api.getIndicatorGroupProps()"> <button v-bind="api.getIndicatorProps({ index: 0 })" /> </div> <button v-bind="api.getNextTriggerProps()"/> </div> </div></template>
import * as carousel from '@destyler/carousel'import { normalizeProps, useMachine } from '@destyler/react'import { useId } from 'react'
export default function Carousel() {
const [state, send] = useMachine( carousel.machine({ id: useId(), }) )
const api = carousel.connect(state, send, normalizeProps)
return ( <> <div {...api.getRootProps()}> <div {...api.getItemGroupProps()}> <div {...api.getItemProps({ index: 0 })}> <img /> </div> </div> <div {...api.getControlProps()}> <button {...api.getPrevTriggerProps()} /> <div {...api.getIndicatorGroupProps()}> <button {...api.getIndicatorProps({ index: 0 })}/> </div> <button {...api.getNextTriggerProps()}/> </div> </div> </> )}
<script lang="ts"> import * as carousel from '@destyler/carousel' import { normalizeProps, useMachine } from '@destyler/svelte'
const uid = $props.id();
const [state, send] = useMachine( carousel.machine({ id: uid, }), )
const api = $derived(carousel.connect(state, send, normalizeProps))</script>
<div {...api.getRootProps()}> <div {...api.getItemGroupProps()}> <div {...api.getItemProps({ index: 0 })}> <img /> </div> </div>
<div {...api.getControlProps()}> <button {...api.getPrevTriggerProps()}> </button> <div {...api.getIndicatorGroupProps()}> <button {...api.getIndicatorProps({ index: 0 })}></button> </div> <button {...api.getNextTriggerProps()}></button> </div></div>
import type { Component } from 'solid-js'import * as carousel from '@destyler/carousel'import { normalizeProps, useMachine } from '@destyler/solid'import { createMemo, createUniqueId } from 'solid-js'
const Carousel: Component = () => {
const [state, send] = useMachine( carousel.machine({ id: createUniqueId(), }))
const api = createMemo(() => carousel.connect(state, send, normalizeProps))
return ( <> <div {...api().getRootProps()}> <div {...api().getItemGroupProps()}> <div {...api().getItemProps({ index: 0 })}> <img /> </div> </div> <div {...api().getControlProps()}> <button {...api().getPrevTriggerProps()} /> <div {...api().getIndicatorGroupProps()}> <button {...api().getIndicatorProps({ index: 0 })}/> </div> <button {...api().getNextTriggerProps()} /> </div> </div> </> )}
export default Carousel
Vertical carousel
To create a vertical carousel, set the orientation
property in the machine’s context to vertical
.
const [state, send] = useMachine( carousel.machine({ orientation: "vertical", }),)
Setting the initial slide
To set the initial slide of the carousel, pass the page
property to the machine’s context.
The page
corresponds to the scroll snap position index based on the layout.
It does not necessarily correspond to the index of the slide in the carousel.
const [state, send] = useMachine( carousel.machine({ page: 2, }),)
Setting the number of slides to show at a time
To customize number of slides to show at a time,
set the slidesPerPage
property in the machine’s context. The value must be an integer.
const [state, send] = useMachine( carousel.machine({ slidesPerPage: 2, }),)
Setting the number of slides to move at a time
To customize number of slides to move at a time,
set the slidesPerMove
property in the machine’s context.
The value must be an integer or auto
.
const [state, send] = useMachine( carousel.machine({ slidesPerMove: 2, }),)
Setting the carousel should loop around
To allow looping of slides, set the loop
property in the machine’s context to true
.
const [state, send] = useMachine( carousel.machine({ loop: true, }),)
Setting the gap between slides
To customize spacing between slides,
set the spacing
property in the machine’s context to a valid CSS unit.
const [state, send] = useMachine( carousel.machine({ spacing: "20px", }),)
Listening for page changes
When the carousel page changes, the onPageChange
callback is invoked.
const [state, send] = useMachine( carousel.machine({ onPageChange(details) { // details => { page: number } console.log("selected page:", details.page) }, }),)
Dragging the carousel
To allow dragging the carousel with the mouse,
set the allowMouseDrag
property in the machine’s context to true
.
const [state, send] = useMachine( carousel.machine({ allowMouseDrag: true, }),)
Autoplaying the carousel
To allow the carousel to autoplay, set the autoplay
property in the machine’s context to true
.
const [state, send] = useMachine( carousel.machine({ autoplay: true, }),)
Alternatively,
you can configure the autoplay interval by setting the delay
property in the machine’s context.
const [state, send] = useMachine( carousel.machine({ autoplay: { delay: 2000 }, }),)
Styling guide
Earlier, we mentioned that each carousel part has a data-part
attribute added
to them to select and style them in the DOM.
[data-part="root"] { /* styles for the root part */}
[data-part="item-group"] { /* styles for the item-group part */}
[data-part="item"] { /* styles for the root part */}
[data-part="control"] { /* styles for the control part */}
[data-part="next-trigger"] { /* styles for the next-trigger part */}
[data-part="prev-trigger"] { /* styles for the prev-trigger part */}
[data-part="indicator-group"] { /* styles for the indicator-group part */}
[data-part="indicator"] { /* styles for the indicator part */}
[data-part="autoplay-trigger"] { /* styles for the autoplay-trigger part */}
Active state
When a carousel’s indicator is active, a data-current
attribute is set on the indicator.
[data-part="indicator"][data-current] { /* styles for the indicator's active state */}
Methods and Properties
Machine Context
The carousel machine exposes the following context properties:
Partial<{ root: string; item(index: number): string; itemGroup: string; nextTrigger: string; prevTrigger: string; indicatorGroup: string; indicator(index: number): string; }>
IntlTranslations
number
number | "auto"
boolean | { delay: number; }
boolean
boolean
number
string
string
(details: PageChangeDetails) => void
number | number[]
"proximity" | "mandatory"
number
(details: DragStatusDetails) => void
(details: AutoplayStatusDetails) => void
"ltr" | "rtl"
string
() => ShadowRoot | Node | Document
Orientation
Machine API
The carousel api
exposes the following methods:
number
number[]
boolean
boolean
boolean
boolean
(index: number, instant?: boolean) => void
(page: number, instant?: boolean) => void
(instant?: boolean) => void
(instant?: boolean) => void
() => number
() => void
() => void
(index: number) => boolean
() => void
Data Attributes
Root
data-scope
data-part
data-orientation
ItemGroup
data-scope
data-part
data-orientation
data-dragging
Item
data-scope
data-part
data-index
data-inview
data-orientation
Control
data-scope
data-part
data-orientation
PrevTrigger
data-scope
data-part
data-orientation
NextTrigger
data-scope
data-part
data-orientation
IndicatorGroup
data-scope
data-part
data-orientation
Indicator
data-scope
data-part
data-orientation
data-index
data-readonly
data-current
AutoplayTrigger
data-scope
data-part
data-orientation
data-pressed