slidev-components

This skill covers using Vue components in Slidev, including all built-in components and how to create custom interactive elements for your presentations.

Safety Notice

This listing is imported from skills.sh public index metadata. Review upstream SKILL.md and repository scripts before running.

Copy this and send it to your AI assistant to learn

Install skill "slidev-components" with this command: npx skills add yoanbernabeu/slidev-skills/yoanbernabeu-slidev-skills-slidev-components

Slidev Components

This skill covers using Vue components in Slidev, including all built-in components and how to create custom interactive elements for your presentations.

When to Use This Skill

  • Adding interactive elements to slides

  • Using built-in Slidev components

  • Creating custom Vue components

  • Building reusable presentation elements

  • Adding dynamic content

Using Components

Components can be used directly in Markdown:

My Slide

<MyComponent />

<Counter :start="5" />

Built-in Components

Arrow

Draws an arrow between points.

<Arrow x1="10" y1="20" x2="100" y2="200" />

<Arrow x1="10" y1="20" x2="100" y2="200" color="#f00" width="3" />

Props:

  • x1 , y1 : Start coordinates

  • x2 , y2 : End coordinates

  • color : Arrow color

  • width : Line width

VDragArrow

Draggable arrow (useful for presentations).

<VDragArrow />

AutoFitText

Automatically adjusts font size to fit container.

<AutoFitText :max="200" :min="50" modelValue="My Text" />

Props:

  • max : Maximum font size

  • min : Minimum font size

  • modelValue : Text content

LightOrDark

Renders different content based on theme.

<LightOrDark> <template #light> <img src="/logo-dark.png" /> </template> <template #dark> <img src="/logo-light.png" /> </template> </LightOrDark>

Link

Navigation link to other slides.

<Link to="42">Go to slide 42</Link>

<Link to="/intro">Go to intro</Link>

SlideCurrentNo / SlidesTotal

Display slide numbers.

Slide <SlideCurrentNo /> of <SlidesTotal />

Toc (Table of Contents)

Generates a table of contents.

<Toc />

<Toc maxDepth="2" />

<Toc mode="onlyCurrentTree" />

Props:

  • maxDepth : Maximum heading depth

  • mode : Display mode (all , onlyCurrentTree , onlySiblings )

Transform

Applies CSS transforms.

<Transform :scale="1.5"> <div>Scaled content</div> </Transform>

<Transform :scale="0.8" :rotate="10"> Rotated and scaled </Transform>

Props:

  • scale : Scale factor

  • rotate : Rotation in degrees

Tweet

Embeds a tweet.

<Tweet id="1234567890" />

<Tweet id="1234567890" scale="0.8" />

Youtube

Embeds a YouTube video.

<Youtube id="dQw4w9WgXcQ" />

<Youtube id="dQw4w9WgXcQ" width="560" height="315" />

Props:

  • id : YouTube video ID

  • width , height : Dimensions

SlidevVideo

Embeds a video file.

<SlidevVideo v-click autoplay controls> <source src="/video.mp4" type="video/mp4" /> </SlidevVideo>

Props:

  • autoplay : Auto-play on slide enter

  • controls : Show video controls

  • loop : Loop video

RenderWhen

Conditional rendering based on context.

<RenderWhen context="slide"> Only visible in slide view </RenderWhen>

<RenderWhen context="presenter"> Only visible in presenter view </RenderWhen>

Context options: slide , presenter , previewNext , print

VDrag

Makes elements draggable.

<VDrag> <div class="p-4 bg-blue-500 text-white"> Drag me! </div> </VDrag>

<VDrag :initialX="100" :initialY="50"> Positioned draggable </VDrag>

Animation Components

VClick

Reveals on click.

<v-click>

Revealed on first click

</v-click>

<v-click at="2">

Revealed on second click

</v-click>

VClicks

Reveals children sequentially.

<v-clicks>

  • First item
  • Second item
  • Third item

</v-clicks>

Props:

  • depth : Depth for nested lists

  • every : Items per click

VAfter

Reveals with the previous element.

<v-click>First</v-click> <v-after>Appears with first</v-after>

VSwitch

Switches between content based on clicks.

<v-switch> <template #1>Step 1 content</template> <template #2>Step 2 content</template> <template #3>Step 3 content</template> </v-switch>

Creating Custom Components

Basic Component

Create components/Counter.vue :

<script setup> import { ref } from 'vue'

const props = defineProps({ start: { type: Number, default: 0 } })

const count = ref(props.start) </script>

<template> <div class="counter"> <button @click="count--">-</button> <span class="count">{{ count }}</span> <button @click="count++">+</button> </div> </template>

<style scoped> .counter { display: flex; align-items: center; gap: 1rem; } button { padding: 0.5rem 1rem; font-size: 1.5rem; cursor: pointer; } .count { font-size: 2rem; min-width: 3rem; text-align: center; } </style>

Usage:

Interactive Counter

<Counter :start="10" />

Component with Slots

<!-- components/Card.vue --> <script setup> defineProps({ title: String, color: { type: String, default: 'blue' } }) </script>

<template> <div :class="card card-${color}"> <h3 v-if="title">{{ title }}</h3> <slot /> </div> </template>

<style scoped> .card { padding: 1.5rem; border-radius: 0.5rem; margin: 1rem 0; } .card-blue { background: #3b82f6; color: white; } .card-green { background: #22c55e; color: white; } .card-red { background: #ef4444; color: white; } </style>

Usage:

<Card title="Important" color="red"> This is a red card with important content. </Card>

Component with Slidev Context

<!-- components/ProgressBar.vue --> <script setup> import { computed } from 'vue' import { useNav } from '@slidev/client'

const { currentSlideNo, total } = useNav()

const progress = computed(() => (currentSlideNo.value / total.value) * 100 ) </script>

<template> <div class="progress-bar"> <div class="progress" :style="{ width: ${progress}% }" /> </div> </template>

<style scoped> .progress-bar { position: fixed; top: 0; left: 0; right: 0; height: 4px; background: #e5e7eb; } .progress { height: 100%; background: #3b82f6; transition: width 0.3s; } </style>

Code Demo Component

<!-- components/CodeDemo.vue --> <script setup> import { ref, computed } from 'vue'

const props = defineProps({ code: String, language: { type: String, default: 'javascript' } })

const output = ref('') const error = ref('')

const run = () => { try { output.value = eval(props.code) error.value = '' } catch (e) { error.value = e.message output.value = '' } } </script>

<template> <div class="code-demo"> <pre><code>{{ code }}</code></pre> <button @click="run">Run</button> <div v-if="output" class="output">{{ output }}</div> <div v-if="error" class="error">{{ error }}</div> </div> </template>

Composables

useNav

Access navigation state:

<script setup> import { useNav } from '@slidev/client'

const { currentSlideNo, // Current slide number total, // Total slides next, // Go to next prev, // Go to previous go // Go to specific slide } = useNav() </script>

useSlideContext

Access slide context:

<script setup> import { useSlideContext } from '@slidev/client'

const { $slidev, // Global context $clicks, // Current click count $page // Current page number } = useSlideContext() </script>

Global Components

global-top.vue

Appears above all slides:

<!-- global-top.vue --> <template> <div class="absolute top-4 right-4"> <img src="/logo.png" class="h-8" /> </div> </template>

global-bottom.vue

Appears below all slides:

<!-- global-bottom.vue --> <template> <footer class="absolute bottom-4 left-4 text-sm opacity-50"> © 2025 My Company </footer> </template>

Component Patterns

Progress Indicator

<div class="fixed bottom-4 right-4 text-sm"> <SlideCurrentNo /> / <SlidesTotal /> </div>

Social Links

<!-- components/SocialLinks.vue --> <template> <div class="flex gap-4"> <a href="https://twitter.com/..." target="_blank"> <carbon-logo-twitter class="text-2xl" /> </a> <a href="https://github.com/..." target="_blank"> <carbon-logo-github class="text-2xl" /> </a> </div> </template>

QR Code

<!-- components/QRCode.vue --> <script setup> import { ref, onMounted } from 'vue' import QRCodeLib from 'qrcode'

const props = defineProps({ url: String, size: { type: Number, default: 200 } })

const qrDataUrl = ref('')

onMounted(async () => { qrDataUrl.value = await QRCodeLib.toDataURL(props.url, { width: props.size }) }) </script>

<template> <img :src="qrDataUrl" :width="size" :height="size" /> </template>

Best Practices

  • Keep Components Simple: Focus on single responsibilities

  • Use Props: Make components configurable

  • Style Scoped: Avoid global style pollution

  • Document Usage: Add comments showing how to use

  • Test Interactivity: Verify components work in presenter mode

Output Format

When creating components, provide:

COMPONENT: [name] PURPOSE: [what it does]

FILE: components/[Name].vue

<script setup> [script content] </script>

<template> [template content] </template>

<style scoped> [styles] </style>

USAGE IN SLIDES:

&#x3C;[Name] prop="value" />

PROPS:

- [propName]: [type] - [description]

Source Transparency

This detail page is rendered from real SKILL.md content. Trust labels are metadata-based hints, not a safety guarantee.

Related Skills

Related by shared tags or category signals.

Coding

slidev-quick-start

No summary provided by upstream source.

Repository SourceNeeds Review
Coding

slidev-styling

No summary provided by upstream source.

Repository SourceNeeds Review
Coding

slidev-syntax-guide

No summary provided by upstream source.

Repository SourceNeeds Review