import SwiperCarousel from "@wikicasa-dev/components/generic/carousel/SwiperCarousel";
Renders data shaped like Image from @wikicasa-dev/types.
The all-in-one carousel. Use it for horizontally swipeable rows of cards ("Visti di recente", agents, testimonials) or a simple photo gallery. Two ways to fill it:
- Slots: put
SwiperSlideelements in the default slot, each holding any content. - Images: pass
images(Image[]from@wikicasa-dev/types, at least{ src, alt }) and leave the default slot empty; it renders one<img>per slide, adds#last_slideafter them, and can add a thumbnail strip withthumb-swiper-options.
Behavior comes from swiper-options (plain Swiper options): slidesPerView, spaceBetween, loop, breakpoints, navigation: true (arrows), pagination: true (bullets) or pagination: { type: "fraction" } ("2 / 8" pill), autoplay, keyboard. Swiper loads after mount; until then the carousel is hidden (display: none) and the #placeholder slot is shown.
Need custom arrows, a deferred-loading gallery or a thumbnail strip with your own slides? Compose the primitives (see SwiperRootPrimitive).
Usage
<script setup lang="ts">
import SwiperCarousel from "@wikicasa-dev/components/generic/carousel/SwiperCarousel";
import SwiperSlide from "@wikicasa-dev/components/generic/carousel/SwiperSlide";
const listings = [
{ id: 1, title: "Bilocale a Firenze", price: "€ 290.000" },
{ id: 2, title: "Trilocale a Bologna", price: "€ 340.000" },
{ id: 3, title: "Villa a Lucca", price: "€ 720.000" },
{ id: 4, title: "Loft a Milano", price: "€ 510.000" },
];
</script>
<template>
<section class="recent">
<SwiperCarousel
id="recently-seen"
:swiper-options="{ slidesPerView: 1.2, spaceBetween: 16, pagination: true, breakpoints: { 768: { slidesPerView: 3 } } }"
>
<SwiperSlide v-for="l in listings" :key="l.id">
<article class="recent__card"><h3>{{ l.title }}</h3><p>{{ l.price }}</p></article>
</SwiperSlide>
<template #placeholder>
<div style="height: 180px" />
</template>
</SwiperCarousel>
</section>
</template>
<style scoped>
.recent :deep(.swiper-wrapper) { padding-bottom: 32px; }
.recent :deep(.swiper-pagination-bullet-active) { --swiper-pagination-color: rgb(var(--uikit-color-w-primary)); }
.recent__card { width: 100%; padding: 16px; border-radius: 20px; background: #fff; }
</style>
Do / Don't
- Don't put
classonSwiperCarousel: it is ignored. Use these kebab-case attributes instead (camelCase is ignored too):root-classes(outer wrapper),swiper-classes(the.swiperelement),swiper-wrapper-classes,swiper-pagination-classes; in images mode alsoswiper-slide-classes,slide-img-classes,thumb-swiper-classes,thumb-img-wrapper-classes,thumb-img-classes. - Scoped styles of your component don't reach the carousel's internal elements, even through the
*-classesattributes: pass global classes there, or style from a wrapper you own with:deep()as above. Slide content you write in the slot is yours and scoped normally. - Do fill
#placeholderwith a box of the carousel's final height, or the page jumps when it appears. - Do treat
swiper-optionsas fixed: it's read once. To change slides per view later, call the exposedupdateSlidesPerView(n); to jump,moveTo(index); for anything else the exposedswiperis the Swiper instance. - Do key slides by a stable id, not the index.
- Don't put
SwiperSlideImagePrimitivewithlazyin it: its images never load here. Use plain<img>or the primitives. - Active pagination bullets are white by default: on light backgrounds override
--swiper-pagination-coloras above.
Styling hooks
Swiper's own CSS variables, set on an ancestor or on the elements (use :deep() from scoped styles, Swiper adds these classes at runtime): --swiper-pagination-color (active bullet), --swiper-pagination-bullet-inactive-color, --swiper-pagination-bullet-inactive-opacity, --swiper-pagination-bullet-width / -height, --swiper-pagination-bottom, --swiper-navigation-color, --swiper-navigation-size, --swiper-navigation-sides-offset. Thumbnail of the active slide: .swiper-slide-thumb-active.
API
Generated from the component's types. Do not edit by hand.
Props
| Name | Type | Default | Required | Description |
|---|---|---|---|---|
id |
string |
|||
swiperOptions |
SwiperOptions |
yes | ||
thumbSwiperOptions |
SwiperOptions |
|||
lazyLoadImages |
boolean |
true |
||
backgroundImage |
boolean |
false |
||
images |
Image[] |
[] |
||
artDirection |
Record<string, { mq: string; width: string; }> |
|||
shiftFirstImage |
boolean |
false |
Events
| Name | Payload |
|---|---|
click |
|
moved |
[{ activeIndex: number; }] |
firstSlideLoaded |
|
init |
v-model
None.
Slots
| Name | Slot props |
|---|---|
default |
|
last_slide |
|
placeholder |
Exposed (template ref)
| Name | Type |
|---|---|
swiper |
Nullable<Swiper> |
moveTo |
(index: number, speed?: number, runCallbacks?: boolean) => void |
updateSlidesPerView |
(value: number) => void |