Virtual Rendering
AdvancedEfficiently handle large datasets with virtual DOM rendering.
Demo
Source
vue
<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"
:render-limit="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>vue
<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>Key Concepts
- renderLimit: Maximum number of cards rendered in DOM
- Only renders visible + upcoming cards
- Dramatically improves performance with 1000+ items
- Maintains smooth animations regardless of dataset size
Performance
| Cards | Without renderLimit | With renderLimit=5 |
|---|---|---|
| 100 | ~100 DOM nodes | ~5 DOM nodes |
| 1,000 | ~1,000 DOM nodes | ~5 DOM nodes |
| 10,000 | ~10,000 DOM nodes | ~5 DOM nodes |