@wikicasa-dev/components · Media · primitive

SwiperRootPrimitive

Root of the composable Swiper carousel; owns the Swiper instance, deferred image loading and the reveal.

Root of the composable Swiper carousel; owns the Swiper instance, deferred image loading and the reveal.

import SwiperRootPrimitive from "@wikicasa-dev/components/generic/carousel/Primitive/SwiperRootPrimitive";

Build a custom carousel from parts when SwiperCarousel isn't enough: a photo gallery that downloads only the photos near the current one, a thumbnail strip, your own arrow buttons. The parts:

  • SwiperRootPrimitive: creates and destroys the Swiper instance from swiper-options (any Swiper option except pagination/navigation, e.g. slidesPerView, loop, rewind, keyboard, autoplay, zoom, breakpoints). Slots: default (the parts below), #placeholder (laid over the carousel until it is ready), #thumbs (rendered outside the clipped .swiper box).
  • SwiperPrimitive: the slide track; put the slides in it.
  • SwiperSlide (any content) or SwiperSlideImagePrimitive (one image, optionally deferred with lazy).
  • SwiperPaginationPrimitive, SwiperNavigationPrimitive: bullets/fraction and arrows, next to SwiperPrimitive.
  • SwiperThumbnailPrimitive: thumbnail strip linked to the carousel, in #thumbs.

The carousel stays at opacity: 0 (space reserved) until Swiper has started and the active slide's images have loaded (6s at most), then appears. Images with data-src (or SwiperSlideImagePrimitive with lazy) load only when their slide is on screen or within preload-count slides of it.

Usage

<script setup lang="ts">
import SwiperRootPrimitive from "@wikicasa-dev/components/generic/carousel/Primitive/SwiperRootPrimitive";
import SwiperPrimitive from "@wikicasa-dev/components/generic/carousel/Primitive/SwiperPrimitive";
import SwiperSlideImagePrimitive from "@wikicasa-dev/components/generic/carousel/Primitive/SwiperSlideImagePrimitive";
import SwiperPaginationPrimitive from "@wikicasa-dev/components/generic/carousel/Primitive/SwiperPaginationPrimitive";
import SwiperNavigationPrimitive from "@wikicasa-dev/components/generic/carousel/Primitive/SwiperNavigationPrimitive";
import SwiperThumbnailPrimitive from "@wikicasa-dev/components/generic/carousel/Primitive/SwiperThumbnailPrimitive";

const photos = [
  { src: "/img/villa-1.jpg", alt: "Villa a Lucca, facciata" },
  { src: "/img/villa-2.jpg", alt: "Villa a Lucca, soggiorno" },
  { src: "/img/villa-3.jpg", alt: "Villa a Lucca, giardino" },
];
</script>

<template>
  <SwiperRootPrimitive class="gallery" :preload-count="1" :swiper-options="{ slidesPerView: 1, keyboard: { enabled: true } }">
    <SwiperPrimitive>
      <SwiperSlideImagePrimitive
        v-for="(p, i) in photos" :key="p.src" :src="p.src" :alt="p.alt" :width="800" :height="600"
        :lazy="i > 0" :fetchpriority="i === 0 ? 'high' : 'low'" img-classes="gallery__img"
      />
    </SwiperPrimitive>
    <SwiperPaginationPrimitive :options="{ type: 'fraction' }" />
    <SwiperNavigationPrimitive />

    <template #thumbs>
      <SwiperThumbnailPrimitive :swiper-options="{ slidesPerView: 4, spaceBetween: 8, freeMode: true }">
        <SwiperSlideImagePrimitive v-for="p in photos" :key="p.src" :src="p.src" :alt="p.alt" lazy img-classes="gallery__thumb" />
      </SwiperThumbnailPrimitive>
    </template>
  </SwiperRootPrimitive>
</template>

<style scoped>
.gallery :deep(.gallery__img) { width: 100%; height: 480px; object-fit: cover; }
.gallery :deep(.gallery__thumb) { width: 80px; height: 80px; object-fit: cover; border-radius: 8px; }
</style>

Do / Don't

  • Do render pagination, navigation and thumbnail primitives unconditionally: they register with the root while it is being created; adding one later (v-if turning true) has no effect.
  • Do give the first, visible slide's image a real src (not lazy) and fetchpriority="high"; defer the rest.
  • Don't change root-classes after mount (Swiper's own classes on that element would be wiped); put toggling classes on the component itself (class lands on an outer wrapper).
  • Don't listen for @click here (never emitted); put it on SwiperPrimitive. init hands you the Swiper instance (also exposed as swiper), handy for your own prev/next buttons: swiper.slidePrev().
  • Treat swiper-options as fixed; use the exposed updateSlidesPerView(n) to change slides per view.
  • Swiper's stylesheets load with Swiper after mount. A server-rendered carousel whose pre-start layout must already be right imports them itself, as wikicasa-nuxt does: @import "@wikicasa-dev/components/css/swiper-swiper"; (plus swiper-zoom).

Styling hooks

Same Swiper CSS variables as SwiperCarousel (--swiper-pagination-*, --swiper-navigation-*), set with :deep() from a wrapper. The active thumbnail slide has .swiper-slide-thumb-active.

API

Generated from the component's types. Do not edit by hand.

Props

Name Type Default Required Description
rootClasses ClassTypeProp
swiperOptions SwiperRootPrimitiveProps
preloadCount number Slides to promote beyond each edge of the visible window. Falls back to swiperOptions.lazyPreloadPrevNext when unset, which is how this was configured before and stays supported - but that option's documented job is Swiper's own loading="lazy" preloading, which these slides do not use. Prefer this prop.

Events

Name Payload
click
moved [{ activeIndex: number; }]
init [Swiper]

v-model

None.

Slots

Name Slot props
default
placeholder
thumbs

Exposed (template ref)

Name Type
swiper Nullable<Swiper>
updateSlidesPerView (value: number) => void