Now liveThe Skillselion MCP - thousands of ranked skills, loaded into your agent mid-task. No install.Get it →
yoanbernabeu avatar

Slidev Components

  • 132 installs
  • 33 repo stars
  • Updated January 30, 2026
  • yoanbernabeu/slidev-skills

Teaches how to embed Vue components into Slidev markdown presentations, including built-in components and custom interactive elements.

About

slidev-components teaches developers how to use Vue components within Slidev presentations, covering the full built-in component library and the process of building custom interactive elements. Components embed directly into Markdown slide files, enabling dynamic content without complex tooling. Reach for it when you want to add interactive features, reusable elements, or dynamic content to a Slidev presentation and need guidance on the component system.

  • Covers all Slidev built-in components
  • Guides creating custom Vue components for presentations
  • Components embed directly into Markdown slides
  • Enables interactive and dynamic presentation content
  • 109 installs from a 32-star repository

Slidev Components by the numbers

  • 132 all-time installs (skills.sh)
  • +6 installs in the week ending Jul 28, 2026 (Skillselion tracking)
  • Ranked #987 of 2,245 Frontend Development skills by installs in the Skillselion catalog
  • Data as of Jul 28, 2026 (Skillselion catalog sync)
npx skills add https://github.com/yoanbernabeu/slidev-skills --skill slidev-components

Add your badge

Show developers this skill is listed on Skillselion. Paste this into your README.

Listed on Skillselion
Installs132
repo stars33
Last updatedJanuary 30, 2026
Repositoryyoanbernabeu/slidev-skills

What it does

Teaches how to embed Vue components into Slidev markdown presentations, including built-in components and custom interactive elements.

Who is it for?

Best when you're building interactive technical presentations with Slidev

Skip if: Static slide decks without interactivity

What you get

  • Vue component code
  • interactive slide content

Files

SKILL.mdMarkdownGitHub ↗

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

1. Keep Components Simple: Focus on single responsibilities 2. Use Props: Make components configurable 3. Style Scoped: Avoid global style pollution 4. Document Usage: Add comments showing how to use 5. 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:

<[Name] prop="value" />


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

Related skills

This week in AI coding

Five minutes, every Monday - the tools, releases and tactics for developers.

unsubscribe anytime.