Vitral 0.2
Media

Carousel

A track of items with paging and optional rotation, which pauses on demand and while you point at or work in it.

Import

main.ts
import { Carousel } from '@vitral/vue';

Several at once

<script setup lang="ts">import { Carousel } from '@vitral/vue'; const photos = [    { id: 1015, title: 'River valley' },    { id: 1016, title: 'Canyon' },    { id: 1018, title: 'Mountains' },    { id: 1019, title: 'Coast' },    { id: 1020, title: 'Bear' },    { id: 1021, title: 'Fog' },    { id: 1022, title: 'Aurora' },    { id: 1024, title: 'Vulture' }]; const responsive = [    { breakpoint: '1024px', numVisible: 2, numScroll: 2 },    { breakpoint: '640px', numVisible: 1, numScroll: 1 }];</script> <template>    <Carousel :value="photos" :num-visible="3" :num-scroll="3" :responsive-options="responsive" aria-label="Landscapes">        <template #item="{ data }">            <figure style="margin: 0 0.5rem">                <img width="400" height="260" :src="`https://picsum.photos/id/${(data as { id: number }).id}/400/260`" :alt="(data as { title: string }).title" style="display: block; width: 100%; border-radius: 8px; height: auto" />                <figcaption style="font-size: 0.75rem; color: var(--vt-text-muted-color)">{{ (data as { title: string }).title }}</figcaption>            </figure>        </template>    </Carousel></template>

Circular, with rotation

<script setup lang="ts">import { Carousel } from '@vitral/vue'; const photos = [    { id: 1015, title: 'River valley' },    { id: 1016, title: 'Canyon' },    { id: 1018, title: 'Mountains' },    { id: 1019, title: 'Coast' },    { id: 1020, title: 'Bear' },    { id: 1021, title: 'Fog' },    { id: 1022, title: 'Aurora' },    { id: 1024, title: 'Vulture' }];</script> <template>    <Carousel :value="photos" circular :autoplay-interval="3000" aria-label="Featured photo">        <template #item="{ data }">            <img width="900" height="360" :src="`https://picsum.photos/id/${(data as { id: number }).id}/900/360`" :alt="(data as { title: string }).title" style="display: block; width: 100%; border-radius: 8px; height: auto" />        </template>    </Carousel></template>

Vertical

<script setup lang="ts">import { Carousel } from '@vitral/vue'; const photos = [    { id: 1015, title: 'River valley' },    { id: 1016, title: 'Canyon' },    { id: 1018, title: 'Mountains' },    { id: 1019, title: 'Coast' },    { id: 1020, title: 'Bear' },    { id: 1021, title: 'Fog' },    { id: 1022, title: 'Aurora' },    { id: 1024, title: 'Vulture' }];</script> <template>    <Carousel :value="photos" orientation="vertical" :num-visible="2" vertical-view-port-height="22rem" :show-indicators="false" aria-label="Vertical photos" style="max-width: 20rem">        <template #item="{ data }">            <img width="320" height="200" :src="`https://picsum.photos/id/${(data as { id: number }).id}/320/200`" :alt="(data as { title: string }).title" style="display: block; width: 100%; height: 100%; object-fit: cover; padding: 0.25rem 0; box-sizing: border-box" />        </template>    </Carousel></template>

Transitions, one at a time

The default slides the whole strip, which is what lets a carousel show several at once. Every other preset shows one and animates it where it stands, so it applies only where numVisible is 1. They are the same presets Galleria uses.

<script setup lang="ts">import { Carousel, SelectButton, StackPanel, transitionPresets, type TransitionPreset } from '@vitral/vue';import { ref } from 'vue'; const photos = [    { id: 1015, title: 'River valley' },    { id: 1016, title: 'Canyon' },    { id: 1018, title: 'Mountains' },    { id: 1019, title: 'Coast' },    { id: 1020, title: 'Bear' },    { id: 1021, title: 'Fog' },    { id: 1022, title: 'Aurora' },    { id: 1024, title: 'Vulture' }]; const preset = ref<TransitionPreset>('zoom');const presetOptions = transitionPresets.filter((p) => p !== 'none').map((value) => ({ label: value[0]!.toUpperCase() + value.slice(1), value }));</script> <template>    <StackPanel spacing="0.75rem" style="flex: 1 1 100%; min-width: 0">        <SelectButton v-model="preset" :options="presetOptions" option-label="label" option-value="value" size="small" :allow-empty="false" aria-label="Transition" />        <Carousel :value="photos" :num-visible="1" :num-scroll="1" :transition="preset" aria-label="Photographs, with a transition">            <template #item="{ data }">                <figure style="margin: 0">                    <img width="800" height="400" :src="`https://picsum.photos/id/${(data as { id: number }).id}/800/400`" :alt="(data as { title: string }).title" style="display: block; width: 100%; height: auto" />                    <figcaption style="font-size: 0.75rem; color: var(--vt-text-muted-color)">{{ (data as { title: string }).title }}</figcaption>                </figure>            </template>        </Carousel>    </StackPanel></template>

API

Read from packages/vue/src/components/Carousel/types.ts, so it says what the component actually accepts.

Props

NameTypeDescription
valueany[]—
numVisiblenumberItems shown at once. Defaults to 1.
numScrollnumberItems moved per step. Defaults to 1.
responsiveOptionsCarouselResponsiveOption[]Fewer items on smaller screens.
orientation'horizontal' | 'vertical'—
verticalViewPortHeightstringThe viewport's height when vertical. Defaults to `'20rem'`.
circularbooleanWrap round: the last item is followed by the first. On by default — a gallery that stops dead at the end sends the reader back through everything they have just seen to reach the other end of it.
autoplayIntervalnumberMilliseconds between automatic steps; 0 (the default) turns it off.
showNavigatorsbooleanDefaults to true.
showIndicatorsbooleanDefaults to true.
ariaLabelstringNames the carousel.
transitionTransitionPreset | 'slide'How one slide gives way to the next. The default `'slide'` moves the whole strip, which is what lets a carousel show several at once; every other preset shows one at a time and animates it in place, so it applies only where `numVisible` is 1.

Plus pt, dt and unstyled from BaseProps, see pass-through and unstyled mode.

Emits

EventPayloadDescription
update:pagepage: number—

Slots

NameSlot propsDescription
item(props: { data: unknown; index: number })—
header——
footer——
empty——