For Numisma’s “Why choose Numisma” section, I used overlapping cards to keep one feature in focus while showing the cards on either side. Swiper handles the movement and 3D transforms; Vue renders the content.
This is a reusable version of that component, with its card styles included. Drag the cards, click a side card, or use the pagination to change the active feature.
Install Swiper
Start with a Vue 3 project that supports TypeScript and single-file components. This example uses Swiper 12.1.2, the version installed in Numisma.
npm install swiper@12.1.2Build the component
Save this as SwiperWhyNumisma.vue. Each slide has an ID, title, plain-text description, and optional image URL. Keep the card content inside SwiperSlide; Swiper applies its transforms to the slide itself.
<template>
<section class="why-numisma" aria-label="Why choose Numisma">
<h2>Why choose Numisma?</h2>
<Swiper
class="coverflow"
:modules="[EffectCoverflow, Pagination, A11y]"
effect="coverflow"
:grab-cursor="true"
:centered-slides="true"
:slides-per-view="1.2"
:initial-slide="2"
:space-between="0"
:slide-to-clicked-slide="true"
:coverflow-effect="{
rotate: 0,
stretch: 150,
depth: 180,
modifier: 1,
slideShadows: false,
}"
:breakpoints="{
600: { slidesPerView: 2 },
1024: { slidesPerView: 3 },
1536: { slidesPerView: 4 },
}"
:pagination="{ clickable: true }"
>
<SwiperSlide v-for="slide in props.slides" :key="slide.id">
<article class="feature-card">
<img
v-if="slide.icon"
:src="slide.icon"
alt=""
width="64"
height="64"
/>
<h3>{{ slide.title }}</h3>
<p>{{ slide.text }}</p>
</article>
</SwiperSlide>
</Swiper>
</section>
</template>
<script setup lang="ts">
import { Swiper, SwiperSlide } from 'swiper/vue'
import { A11y, EffectCoverflow, Pagination } from 'swiper/modules'
import 'swiper/css'
import 'swiper/css/effect-coverflow'
import 'swiper/css/pagination'
const props = defineProps<{
slides: {
id: string
title: string
text: string
icon?: string
}[]
}>()
</script>
<style scoped>
.why-numisma {
padding: 3rem 0;
overflow: hidden;
background: #102b50;
color: #fff;
}
.why-numisma h2 {
margin: 0 1rem 2rem;
text-align: center;
font-size: 2rem;
}
.coverflow {
padding-bottom: 3rem;
}
.coverflow :deep(.swiper-slide) {
height: auto;
}
.feature-card {
box-sizing: border-box;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
height: 100%;
min-height: 24rem;
padding: 3rem;
border: 4px solid #fbbf24;
border-radius: 1.5rem;
background: linear-gradient(135deg, #e4f0ff, #f6f6f6);
color: #102b50;
text-align: center;
}
.feature-card img {
object-fit: contain;
margin-bottom: 1.5rem;
}
.feature-card h3 {
margin: 0 0 1.5rem;
font-size: clamp(1.5rem, 2vw, 1.875rem);
line-height: 1.2;
}
.feature-card p {
margin: 0;
font-size: 1.125rem;
line-height: 1.5;
}
.coverflow :deep(.swiper-pagination) {
bottom: 0;
}
.coverflow :deep(.swiper-pagination-bullet) {
width: 1rem;
height: 4px;
border-radius: 0;
background: #d1d5db;
opacity: 1;
transition: width 0.3s, background-color 0.3s;
}
.coverflow :deep(.swiper-pagination-bullet-active) {
width: 2rem;
background: #fbbf24;
}
.coverflow :deep(.swiper-pagination-bullet:focus-visible) {
outline: 2px solid #fff;
outline-offset: 4px;
}
@media (min-width: 1024px) {
.coverflow :deep(.swiper-pagination-bullet) {
width: 3rem;
}
.coverflow :deep(.swiper-pagination-bullet-active) {
width: 4rem;
}
}
</style>Import the core, coverflow, and pagination styles. Registering the modules alone does not load their CSS. A11y adds labels and keyboard handling to the pagination controls.
Pass in the cards
In a parent component beside SwiperWhyNumisma.vue, pass the five features from the original section. The descriptions below are Numisma’s copy, included here as card data.
<template>
<SwiperWhyNumisma :slides="slides" />
</template>
<script setup lang="ts">
import SwiperWhyNumisma from './SwiperWhyNumisma.vue'
const slides = [
{
id: 'magxvrza',
title: 'Independent',
text: 'We make decisions we believe are best for you, without any pressure to sell products from third parties.',
},
{
id: 'magxwq9k',
title: 'Transparent Fees',
text: 'We keep it simple: 100% transparency, zero hidden charges.',
},
{
id: 'magxxi6y',
title: 'Qualified & Experienced Team',
text: 'Investment Team of PhDs and Actuaries with over 20 years of market experience.',
},
{
id: 'magxypa8',
title: 'EU Regulated',
text: 'Registered with all the main EU regulators, including Germany (Bafin), Italy (Consob) and France (AMF).',
},
{
id: 'magxzait',
title: 'High Liquidity',
text: 'Your money is held in your name in reputable financial institutions. You can withdraw your money at any time.',
},
]
</script>Numisma also supplies icons from Statamic. To include one, set the optional icon field to its image URL. The empty image alt text avoids repeating the card’s heading.
How the effect works
centeredSlideskeeps the active card in the middle.rotate: 0keeps the cards facing forward.stretch: 150pulls the side cards toward the center, creating the overlap.depth: 180moves cards farther back as they get farther from the center. Perspective makes them appear smaller.modifier: 1leaves the effect at its base strength;slideShadows: falseremoves the generated slide shadows.initialSlide: 2starts on the third card because slide indexes start at zero.
The effect uses one Swiper instance. The component needs no controller or manual animation loop.
Make it responsive
The default slidesPerView: 1.2 shows the active card and part of its neighbors on smaller screens. At viewport widths of 600px, 1024px, and 1536px, the layout changes to two, three, and four slides per view.
Those numbers set the slide widths before the coverflow transforms. Because the cards overlap, they do not mean that many complete cards will be visible. Keep initialSlide outside the breakpoints: it sets the starting position, not the position after a resize.
Style the pagination
Swiper’s Vue component creates the pagination element when pagination is enabled. Using that built-in element keeps each component instance tied to its own controls.
The :deep() selectors reach Swiper’s generated elements from the scoped stylesheet. The active marker is wider and gold, and the slider’s bottom padding leaves room for the controls.
Adjust the effect
Increase depth to push side cards farther back. Reduce stretch to separate the cards, or increase it for more overlap. Check the longest heading and description at each breakpoint before settling on the card padding.
References
Swiper’s Vue integration covers module registration and styles. The coverflow API describes the effect settings.