@wikicasa-dev/components · Media · preferred

SwiperCarousel

Ready-made Swiper carousel for slides or an image gallery, with optional arrows, bullets, autoplay and thumbnails.

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 SwiperSlide elements 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_slide after them, and can add a thumbnail strip with thumb-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 class on SwiperCarousel: it is ignored. Use these kebab-case attributes instead (camelCase is ignored too): root-classes (outer wrapper), swiper-classes (the .swiper element), swiper-wrapper-classes, swiper-pagination-classes; in images mode also swiper-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 *-classes attributes: 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 #placeholder with a box of the carousel's final height, or the page jumps when it appears.
  • Do treat swiper-options as fixed: it's read once. To change slides per view later, call the exposed updateSlidesPerView(n); to jump, moveTo(index); for anything else the exposed swiper is the Swiper instance.
  • Do key slides by a stable id, not the index.
  • Don't put SwiperSlideImagePrimitive with lazy in 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-color as 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