Live Examples
Interactive demos showcasing different features and use cases.
🚀 Basic Usage
Simple swipeable cards with minimal setup.
Source
<script lang="ts" setup>
import { ref } from 'vue'
import { FlashCards } from 'vue3-flashcards'
import BasicCard from './BasicCard.vue'
const cards = ref([
{ text: 'Mathematics', subtitle: 'Basic algebra and geometry', color: 'from-blue-500 to-blue-600' },
{ text: 'Science', subtitle: 'Physics and chemistry fundamentals', color: 'from-green-500 to-green-600' },
{ text: 'Literature', subtitle: 'Classic novels and poetry', color: 'from-purple-500 to-purple-600' },
])
</script>
<template>
<div class="w-full flex justify-center items-center py-20">
<div class="max-w-sm w-full">
<FlashCards :items="cards" #="{ item }">
<BasicCard :item="item" />
</FlashCards>
</div>
</div>
</template>
<script setup lang="ts">
interface CardItem {
text: string
subtitle: string
color: string
}
defineProps<{
item: CardItem
}>()
</script>
<template>
<div class="relative overflow-hidden rounded-2xl shadow-2xl h-64 bg-white dark:bg-gray-800">
<!-- Gradient header -->
<div :class="`bg-gradient-to-r ${item.color} h-20 relative`">
<div class="absolute inset-0 bg-black/10" />
<div class="absolute bottom-3 left-6 text-white">
<div class="w-8 h-8 bg-white/20 rounded-full flex items-center justify-center">
<div class="w-4 h-4 bg-white rounded-full" />
</div>
</div>
</div>
<!-- Card content -->
<div class="p-6 flex flex-col justify-center items-start h-44">
<h2 class="text-2xl font-bold text-gray-800 dark:text-gray-100 mb-2">
{{ item.text }}
</h2>
<p class="text-gray-600 dark:text-gray-300 text-sm leading-relaxed">
{{ item.subtitle }}
</p>
<!-- Card footer -->
<div class="absolute bottom-4 right-6 flex space-x-2">
<div class="w-2 h-2 bg-gray-300 rounded-full" />
<div class="w-2 h-2 bg-gray-300 rounded-full" />
<div class="w-2 h-2 bg-blue-500 rounded-full" />
</div>
</div>
</div>
</template>
🚧 Drag Limits
Demonstrate drag limits with checkboxes to toggle Y dragging (0px) and X dragging (200px) constraints.
Source
<script lang="ts" setup>
import { ref } from 'vue'
import { FlashCards } from 'vue3-flashcards'
import LimitCard from './LimitCard.vue'
import '../assets/index.css'
const cards = ref([
{ text: 'Mathematics', subtitle: 'Basic algebra and geometry', color: 'from-blue-500 to-blue-600' },
{ text: 'Science', subtitle: 'Physics and chemistry fundamentals', color: 'from-green-500 to-green-600' },
{ text: 'Literature', subtitle: 'Classic novels and poetry', color: 'from-purple-500 to-purple-600' },
])
const limitY = ref(true)
const limitX = ref(true)
</script>
<template>
<div class="w-full flex flex-col justify-center items-center py-20 space-y-8">
<div class="flex space-x-6 p-4 bg-gray-100 dark:bg-gray-800 rounded-lg">
<label class="flex items-center space-x-2">
<input v-model="limitY" type="checkbox" class="toggle toggle-primary">
<span class="text-gray-700 dark:text-gray-300">Limit Y (0px)</span>
</label>
<label class="flex items-center space-x-2">
<input v-model="limitX" type="checkbox" class="toggle toggle-primary">
<span class="text-gray-700 dark:text-gray-300">Limit X (200px)</span>
</label>
</div>
<div class="max-w-sm w-full">
<FlashCards
:items="cards"
:max-dragging-x="limitX ? 200 : null"
:max-dragging-y="limitY ? 0 : null"
#="{ item }"
>
<LimitCard :item="item" />
</FlashCards>
</div>
</div>
</template>
<script setup lang="ts">
interface CardItem {
text: string
subtitle: string
color: string
}
defineProps<{
item: CardItem
}>()
</script>
<template>
<div class="relative overflow-hidden rounded-2xl shadow-2xl h-64 bg-white dark:bg-gray-800 transform transition-all duration-300 hover:scale-105">
<!-- Gradient header -->
<div :class="`bg-gradient-to-r ${item.color} h-20 relative`">
<div class="absolute inset-0 bg-black/10" />
<div class="absolute bottom-3 left-6 text-white">
<div class="w-8 h-8 bg-white/20 rounded-full flex items-center justify-center">
<div class="w-4 h-4 bg-white rounded-full" />
</div>
</div>
</div>
<!-- Card content -->
<div class="p-6 flex flex-col justify-center items-start h-44">
<h2 class="text-2xl font-bold text-gray-800 dark:text-gray-100 mb-2">
{{ item.text }}
</h2>
<p class="text-gray-600 dark:text-gray-300 text-sm leading-relaxed">
{{ item.subtitle }}
</p>
<!-- Card footer -->
<div class="absolute bottom-4 right-6 flex space-x-2">
<div class="w-2 h-2 bg-gray-300 rounded-full" />
<div class="w-2 h-2 bg-gray-300 rounded-full" />
<div class="w-2 h-2 bg-blue-500 rounded-full" />
</div>
</div>
</div>
</template>
🔄 FlipCard Integration
Two-sided cards with flip animations. Click to flip, swipe to approve or reject.
Source
<script lang="ts" setup>
import { ref } from 'vue'
import { FlashCards, FlipCard } from 'vue3-flashcards'
import AnswerCard from './AnswerCard.vue'
import QuestionCard from './QuestionCard.vue'
const cards = ref([
{ text: 'What is the capital of France?', back: 'Paris', difficulty: 'Easy', category: 'Geography' },
{ text: 'What is 15 × 8?', back: '120', difficulty: 'Medium', category: 'Mathematics' },
{ text: 'Who wrote "Romeo and Juliet"?', back: 'William Shakespeare', difficulty: 'Easy', category: 'Literature' },
])
const waitAnimationEnd = ref(true)
const invertAxios = ref<false>(false)
</script>
<template>
<div class="w-full flex flex-col justify-center items-center py-20">
<div class="mb-8 bg-white dark:bg-gray-800 p-4 rounded-xl shadow-md">
<label class="flex items-center gap-3 cursor-pointer mb-1">
<input
v-model="waitAnimationEnd"
type="checkbox"
class="toggle toggle-primary"
>
<span class="font-medium text-gray-700 dark:text-gray-300">Wait for animation end</span>
</label>
<label class="flex items-center gap-3 cursor-pointer">
<input
v-model="invertAxios"
type="checkbox"
class="toggle toggle-primary"
>
<span class="font-medium text-gray-700 dark:text-gray-300">Invert axis</span>
</label>
</div>
<div class="max-w-sm w-full">
<FlashCards :items="cards">
<template #default="{ item }">
<FlipCard :wait-animation-end="waitAnimationEnd" :flip-axis="invertAxios ? 'x' : 'y'">
<template #front>
<QuestionCard :item="item" />
</template>
<template #back>
<AnswerCard :item="item" />
</template>
</FlipCard>
</template>
</FlashCards>
</div>
</div>
</template>
<script setup lang="ts">
interface QuizItem {
text: string
back: string
difficulty: string
category: string
}
defineProps<{
item: QuizItem
}>()
</script>
<template>
<div class="relative overflow-hidden rounded-2xl shadow-2xl h-72 bg-gradient-to-br from-blue-500 to-purple-600 text-white transform transition-all duration-300">
<!-- Question mark icon -->
<div class="absolute top-4 right-4 w-8 h-8 bg-white/20 rounded-full flex items-center justify-center">
<span class="text-white font-bold">?</span>
</div>
<!-- Category tag -->
<div class="absolute top-4 left-4">
<span class="px-3 py-1 bg-white/20 rounded-full text-sm font-medium">
{{ item.category }}
</span>
</div>
<!-- Question content -->
<div class="p-6 h-full flex flex-col justify-center items-center text-center">
<h2 class="text-lg font-bold mb-4 leading-relaxed">
{{ item.text }}
</h2>
<div class="text-sm opacity-80">
Tap to reveal answer
</div>
</div>
<!-- Difficulty indicator -->
<div class="absolute bottom-4 left-4">
<div class="flex items-center gap-2">
<div class="w-2 h-2 bg-white rounded-full" />
<div :class="item.difficulty === 'Easy' ? 'w-2 h-2 bg-green-400 rounded-full' : 'w-2 h-2 bg-white/50 rounded-full'" />
<div :class="item.difficulty === 'Medium' ? 'w-2 h-2 bg-yellow-400 rounded-full' : 'w-2 h-2 bg-white/50 rounded-full'" />
<div :class="item.difficulty === 'Hard' ? 'w-2 h-2 bg-red-400 rounded-full' : 'w-2 h-2 bg-white/50 rounded-full'" />
</div>
</div>
</div>
</template>
<script setup lang="ts">
interface QuizItem {
text: string
back: string
difficulty: string
category: string
}
defineProps<{
item: QuizItem
}>()
</script>
<template>
<div class="relative overflow-hidden rounded-2xl shadow-2xl h-72 bg-gradient-to-br from-emerald-500 to-teal-600 text-white transform transition-all duration-300">
<!-- Answer checkmark icon -->
<div class="absolute top-4 right-4 w-8 h-8 bg-white/20 rounded-full flex items-center justify-center">
<span class="text-white font-bold">✓</span>
</div>
<!-- Category tag -->
<div class="absolute top-4 left-4">
<span class="px-3 py-1 bg-white/20 rounded-full text-sm font-medium">
{{ item.category }}
</span>
</div>
<!-- Answer content -->
<div class="p-6 h-full flex flex-col justify-center items-center text-center">
<div class="text-sm opacity-80 mb-2">
Answer:
</div>
<h2 class="text-2xl font-bold mb-4">
{{ item.back }}
</h2>
<div class="text-sm opacity-80">
Swipe to continue
</div>
</div>
<!-- Difficulty indicator -->
<div class="absolute bottom-4 left-4">
<span class="px-2 py-1 bg-white/20 rounded-full text-xs">
{{ item.difficulty }}
</span>
</div>
</div>
</template>
🎮 Custom Actions
Custom action buttons with manual card controls.
Source
<script lang="ts" setup>
import { ref } from 'vue'
import { FlashCards } from 'vue3-flashcards'
import ActionButtons from './ActionButtons.vue'
import LearningCard from './LearningCard.vue'
const cards = ref([
{ id: 1, text: 'Business Strategy', description: 'Learn the fundamentals of strategic planning', icon: '💼' },
{ id: 2, text: 'Data Science', description: 'Master statistical analysis and machine learning', icon: '📊' },
{ id: 3, text: 'UI/UX Design', description: 'Create beautiful and intuitive user experiences', icon: '🎨' },
// { id: 4, text: 'Business Strategy', description: 'Learn the fundamentals of strategic planning', icon: '💼' },
// { id: 5, text: 'Data Science', description: 'Master statistical analysis and machine learning', icon: '📊' },
// { id: 6, text: 'UI/UX Design', description: 'Create beautiful and intuitive user experiences', icon: '🎨' },
// { id: 7, text: 'Business Strategy', description: 'Learn the fundamentals of strategic planning', icon: '💼' },
// { id: 8, text: 'Data Science', description: 'Master statistical analysis and machine learning', icon: '📊' },
// { id: 9, text: 'UI/UX Design', description: 'Create beautiful and intuitive user experiences', icon: '🎨' },
])
const disableDrag = ref(false)
</script>
<template>
<div class="w-full flex justify-center items-center py-20">
<div class="max-w-sm w-full">
<div class="mb-4 flex items-center justify-center">
<label class="flex items-center space-x-2">
<input
v-model="disableDrag"
type="checkbox"
class="toggle toggle-primary"
>
<span>Disable Drag</span>
</label>
</div>
<FlashCards :items="cards" :disable-drag="disableDrag">
<template #default="{ item }">
<LearningCard :item="item" />
</template>
<template #actions="{ approve, reject, restore }">
<ActionButtons
:approve="approve"
:reject="reject"
:restore="restore"
/>
</template>
</FlashCards>
</div>
</div>
</template>
<script setup lang="ts">
interface LearningItem {
text: string
description: string
icon: string
}
defineProps<{
item: LearningItem
}>()
</script>
<template>
<div class="relative overflow-hidden rounded-2xl shadow-xl h-56 bg-white dark:bg-gray-800 transform transition-all duration-300 hover:shadow-2xl border dark:border-gray-700">
<!-- Icon header -->
<div class="absolute top-4 right-4 text-3xl">
{{ item.icon }}
</div>
<!-- Content -->
<div class="p-6 h-full flex flex-col justify-center">
<h3 class="text-xl font-bold text-gray-800 dark:text-gray-100 mb-3">
{{ item.text }}
</h3>
<p class="text-gray-600 dark:text-gray-300 text-sm leading-relaxed">
{{ item.description }}
</p>
</div>
<!-- Subtle decoration -->
<div class="absolute bottom-0 left-0 w-full h-1 bg-gradient-to-r from-blue-500 to-purple-500" />
</div>
</template>
<script setup lang="ts">
defineProps<{
approve: () => void
reject: () => void
restore: () => void
}>()
</script>
<template>
<div class="grid grid-cols-2 gap-4 mt-6">
<button
class="px-6 py-3 bg-red-500 hover:bg-red-600 text-white rounded-xl font-medium transition-all duration-200 transform hover:scale-105 active:scale-95 shadow-lg"
@click="reject"
>
❌ Skip
</button>
<button
class="px-6 py-3 bg-emerald-500 hover:bg-emerald-600 text-white rounded-xl font-medium transition-all duration-200 transform hover:scale-105 active:scale-95 shadow-lg"
@click="approve"
>
✅ Learn
</button>
<button
class="col-span-2 px-6 py-3 bg-gray-500 hover:bg-gray-600 text-white rounded-xl font-medium transition-all duration-200 transform hover:scale-105 active:scale-95 shadow-lg"
@click="restore"
>
↩️ Restore Last
</button>
</div>
</template>
⚡ Virtual Rendering
Efficient rendering for large datasets (10,000+ cards).
Source
<script setup lang="ts">
import { ref } from 'vue'
import { FlashCards } from 'vue3-flashcards'
import VirtualCard from './VirtualCard.vue'
// Generate 1000 cards for demonstration
const cards = ref(Array.from({ length: 1000 }, (_, i) => ({
id: i + 1,
text: `Card ${i + 1} of 1000`,
})))
const approved = ref<number[]>([])
const rejected = ref<number[]>([])
function onApprove(card: { id: number }) {
approved.value.push(card.id)
}
function onReject(card: { id: number }) {
rejected.value.push(card.id)
}
</script>
<template>
<div class="w-full flex justify-center items-center min-h-[500px] p-5">
<div class="max-w-[400px] w-full isolate">
<FlashCards
:items="cards"
:virtual-buffer="2"
#="{ item }"
@approve="onApprove"
@reject="onReject"
>
<VirtualCard
:item="item"
:approved="approved.length"
:rejected="rejected.length"
:remaining="cards.length - approved.length - rejected.length"
:progress="((approved.length + rejected.length) / cards.length) * 100"
/>
</FlashCards>
</div>
</div>
</template>
<script setup lang="ts">
interface VirtualItem {
id: number
text: string
}
defineProps<{
item: VirtualItem
approved: number
rejected: number
remaining: number
progress: number
}>()
</script>
<template>
<div class="relative overflow-hidden rounded-2xl shadow-xl h-80 bg-gradient-to-br from-slate-800 to-slate-900 text-white select-none transform transition-all duration-300 hover:shadow-2xl">
<!-- Header with number -->
<div class="absolute top-0 left-0 w-full h-16 bg-gradient-to-r from-cyan-500 to-blue-500">
<div class="absolute inset-0 bg-black/10" />
<div class="absolute top-3 left-4 text-white font-bold text-lg">
#{{ item.id }}
</div>
<div class="absolute top-3 right-4 text-white/80 text-sm">
Virtual Demo
</div>
</div>
<!-- Main content -->
<div class="pt-20 p-6 h-full flex flex-col justify-center">
<div class="card-text text-center mb-8">
<h2 class="text-xl font-bold mb-2">
{{ item.text }}
</h2>
<div class="text-cyan-400 text-sm">
Performance test with 1000 cards
</div>
</div>
<!-- Stats grid -->
<div class="card-stats grid grid-cols-3 gap-3 text-center mb-4">
<div class="bg-emerald-500/20 rounded-lg p-3">
<div class="text-emerald-400 text-2xl font-bold">
{{ approved }}
</div>
<div class="text-emerald-300 text-xs">
Approved
</div>
</div>
<div class="bg-red-500/20 rounded-lg p-3">
<div class="text-red-400 text-2xl font-bold">
{{ rejected }}
</div>
<div class="text-red-300 text-xs">
Rejected
</div>
</div>
<div class="bg-blue-500/20 rounded-lg p-3">
<div class="text-blue-400 text-2xl font-bold">
{{ remaining }}
</div>
<div class="text-blue-300 text-xs">
Remaining
</div>
</div>
</div>
</div>
<!-- Progress bar -->
<div class="absolute bottom-0 left-0 w-full h-1 bg-slate-700">
<div
class="h-full bg-gradient-to-r from-cyan-500 to-blue-500 transition-all duration-300"
:style="{ width: `${progress}%` }"
/>
</div>
</div>
</template>
💖 Tinder-Style Cards
Image-based cards with visual swipe indicators and smooth animations.
Source
<script setup lang="ts">
import { ref } from 'vue'
import { FlashCards } from 'vue3-flashcards'
import TinderActions from './TinderActions.vue'
import TinderCard from './TinderCard.vue'
interface Card {
id: number
text: string
description: string
image: string
}
const items = ref<Card[]>([
{
id: 1,
text: 'Mountain Adventure',
description: 'Explore the peaks and valleys',
image: 'https://images.unsplash.com/photo-1464822759023-fed622ff2c3b?w=800&q=80',
},
{
id: 2,
text: 'Beach Paradise',
description: 'Relax by the ocean',
image: 'https://images.unsplash.com/photo-1507525428034-b723cf961d3e?w=800&q=80',
},
{
id: 3,
text: 'City Life',
description: 'Urban exploration',
image: 'https://images.unsplash.com/photo-1449824913935-59a10b8d2000?w=800&q=80',
},
{
id: 4,
text: 'Forest Retreat',
description: 'Connect with nature',
image: 'https://images.unsplash.com/photo-1511497584788-876760111969?w=800&q=80',
},
])
</script>
<template>
<div class="max-w-[400px] mx-auto p-5">
<div class="relative mb-5">
<FlashCards :items="items">
<template #default="{ item }">
<TinderCard :item="item" />
</template>
<template #empty>
<div class="text-center text-xl text-gray-600 p-10">
No more cards!
</div>
</template>
<template #actions="{ approve, reject, restore, isEnd, canRestore }">
<TinderActions
:approve="approve"
:reject="reject"
:restore="restore"
:is-end="isEnd"
:can-restore="canRestore"
/>
</template>
</FlashCards>
</div>
</div>
</template>
<script setup lang="ts">
interface TinderItem {
id: number
text: string
description: string
image: string
}
defineProps<{
item: TinderItem
}>()
</script>
<template>
<div
class="w-full h-[500px] bg-cover bg-center rounded-xl relative overflow-hidden"
:style="{ backgroundImage: `url(${item.image})` }"
>
<div
class="absolute bottom-0 left-0 right-0 p-5 text-white bg-gradient-to-t from-black/80 to-transparent"
>
<h2 class="m-0 mb-2 text-2xl font-semibold">
{{ item.text }}
</h2>
<p class="m-0 text-base">
{{ item.description }}
</p>
</div>
</div>
</template>
<script setup lang="ts">
defineProps<{
approve: () => void
reject: () => void
restore: () => void
isEnd: boolean
canRestore: boolean
}>()
</script>
<template>
<div class="flex justify-center gap-5 mt-5">
<button
class="w-15 h-15 rounded-full text-2xl text-white bg-blue-500 transition-transform duration-200 disabled:opacity-50 disabled:cursor-not-allowed hover:scale-110"
:disabled="!canRestore"
@click="restore"
>
↺
</button>
<button
class="w-15 h-15 rounded-full text-2xl text-white bg-red-500 transition-transform duration-200 disabled:opacity-50 disabled:cursor-not-allowed hover:scale-110"
:disabled="isEnd"
@click="reject"
>
✕
</button>
<button
class="w-15 h-15 rounded-full text-2xl text-white bg-green-500 transition-transform duration-200 disabled:opacity-50 disabled:cursor-not-allowed hover:scale-110"
:disabled="isEnd"
@click="approve"
>
♥
</button>
</div>
</template>
🎯 Delta Usage
Custom swiping indicators with dynamic opacity transitions.
Source
<script lang="ts" setup>
import { ref } from 'vue'
import { FlashCards } from 'vue3-flashcards'
import LanguageCard from './LanguageCard.vue'
import SwipeOverlay from './SwipeOverlay.vue'
interface WordCard {
word: string
translation: string
}
const cards = ref<WordCard[]>([
{ word: 'Hello', translation: 'Bonjour' },
{ word: 'World', translation: 'Monde' },
{ word: 'Thank you', translation: 'Merci' },
{ word: 'Goodbye', translation: 'Au revoir' },
{ word: 'Please', translation: 'S\'il vous plaît' },
])
</script>
<template>
<div class="w-full flex justify-center items-center py-20">
<div class="max-w-sm w-full">
<FlashCards :items="cards">
<template #default="{ item }">
<LanguageCard :item="item" />
</template>
<template #approve="{ delta }">
<SwipeOverlay :delta="Math.abs(delta)" type="approve" />
</template>
<template #reject="{ delta }">
<SwipeOverlay :delta="Math.abs(delta)" type="reject" />
</template>
</FlashCards>
</div>
</div>
</template>
<script setup lang="ts">
interface WordCard {
word: string
translation: string
}
defineProps<{
item: WordCard
}>()
</script>
<template>
<div class="relative overflow-hidden rounded-2xl shadow-xl h-48 bg-gradient-to-br from-indigo-500 to-purple-600 text-white transform transition-all duration-300">
<!-- Language indicator -->
<div class="absolute top-4 left-4 px-3 py-1 bg-white/20 rounded-full text-sm font-medium">
EN → FR
</div>
<!-- Book icon -->
<div class="absolute top-4 right-4 text-white/80">
📚
</div>
<!-- Content -->
<div class="p-6 h-full flex flex-col justify-center items-center gap-3 text-center">
<div class="text-3xl font-bold mb-2">
{{ item.word }}
</div>
<div class="text-xl text-indigo-100">
{{ item.translation }}
</div>
</div>
<!-- Swipe indicators -->
<div class="absolute bottom-4 left-1/2 transform -translate-x-1/2 flex gap-2">
<div class="w-2 h-2 bg-white/40 rounded-full" />
<div class="w-2 h-2 bg-white/60 rounded-full" />
<div class="w-2 h-2 bg-white rounded-full" />
</div>
</div>
</template>
<script setup lang="ts">
defineProps<{
delta: number
type: 'approve' | 'reject'
}>()
</script>
<template>
<div
v-if="type === 'approve'"
class="absolute inset-0 flex items-center justify-center bg-emerald-500/90 rounded-2xl font-bold text-2xl text-white backdrop-blur-sm"
:style="{ opacity: delta }"
>
<div class="text-center">
<div class="text-4xl mb-2">
✅
</div>
<div>I know this!</div>
</div>
</div>
<div
v-else
class="absolute inset-0 flex items-center justify-center bg-red-500/90 rounded-2xl font-bold text-2xl text-white backdrop-blur-sm"
:style="{ opacity: delta }"
>
<div class="text-center">
<div class="text-4xl mb-2">
📚
</div>
<div>Need to review</div>
</div>
</div>
</template>
📏 Scale Transform
Custom transform that scales cards instead of rotating them during swipe gestures.
Source
<script setup lang="ts">
import type { DragPosition } from 'vue3-flashcards'
import { ref } from 'vue'
import { FlashCards } from 'vue3-flashcards'
import ScaleCard from './ScaleCard.vue'
const cards = ref([
{ id: 1, title: 'Scale Transform', description: 'This card scales instead of rotating when swiped' },
{ id: 2, title: 'Custom Animation', description: 'Demonstrates transformStyle prop override' },
{ id: 3, title: 'No Rotation', description: 'Only scaling and translation applied' },
])
// Custom transform function that scales the card instead of rotating
function scaleTransform({ delta }: DragPosition) {
const scale = 1 - (Math.abs(delta) * 0.2)
return `transform: scale(${scale})`
}
</script>
<template>
<div class="w-full flex justify-center items-center py-20">
<div class="max-w-sm w-full">
<FlashCards
:items="cards"
:transform-style="scaleTransform"
>
<template #default="{ item }">
<ScaleCard :card="item" />
</template>
</FlashCards>
</div>
</div>
</template>
<script setup lang="ts">
interface Card {
id: number
title: string
description: string
}
defineProps<{
card: Card
}>()
</script>
<template>
<div class="card bg-gradient-to-br from-primary to-secondary text-primary-content shadow-2xl h-80 relative overflow-hidden">
<div class="card-body p-6">
<div class="flex justify-between items-center mb-4">
<h4 class="card-title text-2xl font-bold">
{{ card.title }}
</h4>
<div class="badge badge-outline badge-lg">
#{{ card.id }}
</div>
</div>
<p class="text-primary-content/90 text-lg leading-relaxed flex-1">
{{ card.description }}
</p>
<div class="card-actions justify-center mt-4">
<span class="text-sm italic opacity-70">
Swipe left or right
</span>
</div>
</div>
</div>
</template>
📚 Stack Configuration
Interactive stack controls with adjustable size (3-10 cards) and directional positioning (top, bottom, left, right).
Source
<script lang="ts" setup>
import { ref } from 'vue'
import { FlashCards } from 'vue3-flashcards'
import StackCard from './StackCard.vue'
const stackSize = ref(5)
const stackDirection = ref<'top' | 'bottom' | 'left' | 'right'>('bottom')
const cards = ref([
{ id: 1, title: 'Project Alpha', color: 'from-blue-500 to-cyan-500', icon: '🚀' },
{ id: 2, title: 'Design System', color: 'from-purple-500 to-pink-500', icon: '🎨' },
{ id: 3, title: 'Data Analytics', color: 'from-green-500 to-emerald-500', icon: '📊' },
{ id: 4, title: 'Machine Learning', color: 'from-orange-500 to-red-500', icon: '🤖' },
{ id: 5, title: 'Cloud Infrastructure', color: 'from-teal-500 to-blue-500', icon: '☁️' },
{ id: 6, title: 'Security Audit', color: 'from-red-500 to-pink-500', icon: '🔒' },
{ id: 7, title: 'API Integration', color: 'from-indigo-500 to-purple-500', icon: '🔗' },
{ id: 8, title: 'User Experience', color: 'from-yellow-500 to-orange-500', icon: '✨' },
])
const directions = [
{ value: 'top', label: 'Top' },
{ value: 'bottom', label: 'Bottom' },
{ value: 'left', label: 'Left' },
{ value: 'right', label: 'Right' },
]
</script>
<template>
<div class="w-full py-16">
<!-- Controls -->
<div class="max-w-sm mx-auto mb-8 px-4">
<div class="bg-white dark:bg-gray-800 rounded-xl p-4 shadow border border-gray-200 dark:border-gray-700">
<div class="space-y-4">
<!-- Stack Size -->
<div>
<label class="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-2">
Stack Size: {{ stackSize }}
</label>
<input
v-model.number="stackSize"
type="range"
min="1"
max="10"
step="1"
class="w-full appearance-none h-2 rounded-lg bg-gray-200 accent-blue-500 cursor-pointer"
>
</div>
<!-- Direction -->
<div>
<label class="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-2">
Direction
</label>
<select
v-model="stackDirection"
class="w-full px-3 py-2 rounded-lg border border-gray-300 dark:border-gray-600 bg-white dark:bg-gray-700 text-gray-900 dark:text-gray-100 text-sm"
>
<option v-for="direction in directions" :key="direction.value" :value="direction.value">
{{ direction.label }}
</option>
</select>
</div>
</div>
</div>
</div>
<!-- FlashCards Demo -->
<div class="flex justify-center items-center min-h-[300px]">
<div class="max-w-xs w-full px-4">
<FlashCards
:items="cards"
:stack="stackSize"
:stack-direction="stackDirection"
:infinite="true"
#="{ item }"
>
<StackCard :item="item" />
</FlashCards>
</div>
</div>
</div>
</template>
<script setup lang="ts">
interface StackItem {
id: number
title: string
color: string
icon: string
}
defineProps<{
item: StackItem
}>()
</script>
<template>
<div class="relative overflow-hidden rounded-2xl shadow-lg h-48 bg-white dark:bg-gray-800 border border-gray-200 dark:border-gray-700">
<!-- Card content -->
<div class="p-6 flex flex-col justify-center items-center h-full text-center">
<div :class="`w-16 h-16 rounded-2xl bg-gradient-to-r ${item.color} flex items-center justify-center shadow-md mb-4`">
<span class="text-3xl">{{ item.icon }}</span>
</div>
<h3 class="text-xl font-bold text-gray-900 dark:text-gray-100 mb-2">
{{ item.title }}
</h3>
<div class="text-xs font-medium text-gray-500 dark:text-gray-400 uppercase tracking-wider">
Card #{{ item.id }}
</div>
</div>
</div>
</template>
♾️ Infinite Swiping
Endless card swiping with only 3 cards that loop infinitely.
Source
<script lang="ts" setup>
import { ref } from 'vue'
import { FlashCards } from 'vue3-flashcards'
import InfiniteCard from './InfiniteCard.vue'
const cards = ref([
{ id: 1, text: 'A', color: 'from-red-500 to-red-600' },
{ id: 2, text: 'B', color: 'from-green-500 to-green-600' },
{ id: 3, text: 'C', color: 'from-blue-500 to-blue-600' },
])
</script>
<template>
<div class="w-full flex justify-center items-center py-12">
<div class="w-80 h-80">
<FlashCards :items="cards" infinite #="{ item }">
<InfiniteCard :item="item" />
</FlashCards>
</div>
</div>
</template>
<script setup lang="ts">
interface CardItem {
text: string
color: string
}
defineProps<{
item: CardItem
}>()
</script>
<template>
<div class="relative overflow-hidden rounded-2xl shadow-lg w-72 h-72 transform transition-all duration-300 hover:scale-105">
<div :class="`bg-gradient-to-br ${item.color} h-full relative flex items-center justify-center`">
<div class="absolute top-2 right-2 text-white/80">
<div class="text-xs">
∞
</div>
</div>
<div class="text-white text-lg font-bold">
{{ item.text }}
</div>
</div>
</div>
</template>
🎭 Transition Effects
Custom transition animations with fast rotating, scaling, 3D flips, and elastic bounce effects.
Source
<script setup>
import { ref } from 'vue'
import FlashCards from '../../src/FlashCards.vue'
import TransitionCard from './TransitionCard.vue'
const selectedTransition = ref('fast-rotate')
const cards = [
{ id: 1, title: 'Fast Rotate', description: 'Cards spin rapidly while exiting', color: '#FF6B6B' },
{ id: 2, title: 'Scale to Zero', description: 'Cards shrink to nothing', color: '#4ECDC4' },
{ id: 3, title: '3D Flip', description: 'Cards flip in 3D space', color: '#45B7D1' },
{ id: 4, title: 'Elastic Bounce', description: 'Cards bounce with elastic effect', color: '#FFA726' },
{ id: 5, title: 'Custom Effects', description: 'Combine multiple animations', color: '#AB47BC' },
]
</script>
<template>
<div class="max-w-lg mx-auto p-6 transition-effects-example">
<div class="text-center mb-8">
<h2 class="text-3xl font-bold text-base-content mb-2">
Custom Transition Effects
</h2>
<p class="text-base-content/70">
Experiment with different transition styles
</p>
</div>
<div class="bg-base-200 p-6 rounded-2xl mb-8">
<div class="grid grid-cols-2 gap-4">
<label class="label cursor-pointer">
<input
v-model="selectedTransition"
type="radio"
value="fast-rotate"
class="radio radio-primary"
>
<span class="label-text ml-2">Fast Rotate</span>
</label>
<label class="label cursor-pointer">
<input
v-model="selectedTransition"
type="radio"
value="scale-out"
class="radio radio-secondary"
>
<span class="label-text ml-2">Scale to Zero</span>
</label>
<label class="label cursor-pointer">
<input
v-model="selectedTransition"
type="radio"
value="flip-3d"
class="radio radio-accent"
>
<span class="label-text ml-2">3D Flip</span>
</label>
<label class="label cursor-pointer">
<input
v-model="selectedTransition"
type="radio"
value="elastic-bounce"
class="radio radio-info"
>
<span class="label-text ml-2">Elastic Bounce</span>
</label>
</div>
</div>
<div class="h-96 w-full relative">
<FlashCards
:items="cards"
:class="selectedTransition"
infinite
>
<template #default="{ item }">
<TransitionCard :card="item" />
</template>
</FlashCards>
</div>
</div>
</template>
<style>
/* Fast Rotate Animation */
.fast-rotate .flash-card__animation-wrapper--approve { animation: fast-rotate-approve 0.4s linear forwards !important; transform-origin: 50% 50% !important; }
.fast-rotate .flash-card__animation-wrapper--reject { animation: fast-rotate-reject 0.4s linear forwards !important; transform-origin: 50% 50% !important; }
.fast-rotate .flash-card__animation-wrapper--restore-approve { animation: fast-rotate-restore-approve 0.4s linear forwards !important; transform-origin: 50% 50% !important; }
.fast-rotate .flash-card__animation-wrapper--restore-reject { animation: fast-rotate-restore-reject 0.4s linear forwards !important; transform-origin: 50% 50% !important; }
@keyframes fast-rotate-approve { 0%{opacity:1;} 100%{transform:translateX(300px) rotate(360deg);opacity:0;} }
@keyframes fast-rotate-reject { 0%{opacity:1;} 100%{transform:translateX(-300px) rotate(-360deg);opacity:0;} }
@keyframes fast-rotate-restore-approve { 0%{transform:translateX(300px) rotate(360deg);opacity:0;} 100%{transform:translateX(0) rotate(0deg);opacity:1;} }
@keyframes fast-rotate-restore-reject { 0%{transform:translateX(-300px) rotate(-360deg);opacity:0;} 100%{transform:translateX(0) rotate(0deg);opacity:1;} }
/* Scale Out Animation */
.scale-out .flash-card__animation-wrapper--approve { animation: scale-out-approve 0.3s cubic-bezier(0.25,0.46,0.45,0.94) forwards !important; }
.scale-out .flash-card__animation-wrapper--reject { animation: scale-out-reject 0.3s cubic-bezier(0.25,0.46,0.45,0.94) forwards !important; }
.scale-out .flash-card__animation-wrapper--restore-approve { animation: scale-out-restore-approve 0.3s cubic-bezier(0.25,0.46,0.45,0.94) forwards !important; }
.scale-out .flash-card__animation-wrapper--restore-reject { animation: scale-out-restore-reject 0.3s cubic-bezier(0.25,0.46,0.45,0.94) forwards !important; }
@keyframes scale-out-approve { 0%{opacity:1;} 100%{transform:translateX(300px) scale(0);opacity:0;} }
@keyframes scale-out-reject { 0%{opacity:1;} 100%{transform:translateX(-300px) scale(0);opacity:0;} }
@keyframes scale-out-restore-approve { 0%{transform:translateX(300px) scale(0);opacity:0;} 100%{transform:translateX(0) scale(1);opacity:1;} }
@keyframes scale-out-restore-reject { 0%{transform:translateX(-300px) scale(0);opacity:0;} 100%{transform:translateX(0) scale(1);opacity:1;} }
/* 3D Flip Animation */
.flip-3d .flash-card__animation-wrapper--approve { animation: flip-3d-approve 0.5s ease-in-out forwards !important; }
.flip-3d .flash-card__animation-wrapper--reject { animation: flip-3d-reject 0.5s ease-in-out forwards !important; }
.flip-3d .flash-card__animation-wrapper--restore-approve { animation: flip-3d-restore-approve 0.5s ease-in-out forwards !important; }
.flip-3d .flash-card__animation-wrapper--restore-reject { animation: flip-3d-restore-reject 0.5s ease-in-out forwards !important; }
@keyframes flip-3d-approve { 0%{opacity:1;} 100%{transform:translateX(300px) rotateY(180deg) rotateX(45deg);opacity:0;} }
@keyframes flip-3d-reject { 0%{opacity:1;} 100%{transform:translateX(-300px) rotateY(-180deg) rotateX(45deg);opacity:0;} }
@keyframes flip-3d-restore-approve { 0%{transform:translateX(300px) rotateY(180deg) rotateX(45deg);opacity:0;} 100%{transform:translateX(0) rotateY(0deg) rotateX(0deg);opacity:1;} }
@keyframes flip-3d-restore-reject { 0%{transform:translateX(-300px) rotateY(-180deg) rotateX(45deg);opacity:0;} 100%{transform:translateX(0) rotateY(0deg) rotateX(0deg);opacity:1;} }
/* Elastic Bounce Animation */
.elastic-bounce .flash-card__animation-wrapper--approve { animation: elastic-bounce-approve 0.6s cubic-bezier(0.68,-0.55,0.265,1.55) forwards !important; }
.elastic-bounce .flash-card__animation-wrapper--reject { animation: elastic-bounce-reject 0.4s cubic-bezier(0.55,0.055,0.675,0.19) forwards !important; }
.elastic-bounce .flash-card__animation-wrapper--restore-approve { animation: elastic-bounce-restore-approve 0.6s cubic-bezier(0.68,-0.55,0.265,1.55) forwards !important; }
.elastic-bounce .flash-card__animation-wrapper--restore-reject { animation: elastic-bounce-restore-reject 0.4s cubic-bezier(0.55,0.055,0.675,0.19) forwards !important; }
@keyframes elastic-bounce-approve { 0%{opacity:1;} 100%{transform:translateX(300px) scale(1.3) rotate(15deg);opacity:0;} }
@keyframes elastic-bounce-reject { 0%{opacity:1;} 100%{transform:translateX(-300px) scale(1.3) rotate(-15deg);opacity:0;} }
@keyframes elastic-bounce-restore-approve { 0%{transform:translateX(300px) scale(1.3) rotate(15deg);opacity:0;} 100%{transform:translateX(0) scale(1) rotate(0deg);opacity:1;} }
@keyframes elastic-bounce-restore-reject { 0%{transform:translateX(-300px) scale(1.3) rotate(-15deg);opacity:0;} 100%{transform:translateX(0) scale(1) rotate(0deg);opacity:1;} }
</style>
<script setup>
defineProps({
card: {
type: Object,
required: true,
},
})
</script>
<template>
<div
class="card size-full text-white shadow-xl"
:style="{ backgroundColor: card.color }"
>
<div class="card-body">
<h2 class="card-title">
{{ card.title }}
</h2>
<p>{{ card.description }}</p>
<div class="card-actions justify-end">
<div class="badge badge-outline">
#{{ card.id }}
</div>
</div>
</div>
</div>
</template>