Advanced Slides with Slidev

I recently spoke at ReactNext and NodeTLV conferences, and Slidev was instrumental in making those presentations engaging and interactive. The ability to embed live code editors, create smooth animations, and maintain slides as code gave me capabilities that traditional presentation tools simply can’t match. In this guide, I’ll share the advanced techniques and features that made those presentations possible.

Why Slidev?

Slidev combines the simplicity of Markdown with the power of Vue.js, making it ideal for technical presentations. Unlike traditional presentation tools, Slidev treats your slides as code, giving you version control, reusable components, and the ability to embed actual running code in your presentations.

Getting Started

Create your first presentation in seconds:

pnpm create slidev

This generates a basic template with slides.md. For a more advanced starting point, explore antfu’s talks repository which showcases professional presentation patterns.

Basic Setup & Workflow

IDE Support

The Slidev VSCode extension is essential for an optimal workflow. It provides live previews, syntax highlighting, and autocompletion directly in your editor.

vscode slidev

Since slides are Markdown files, you can leverage familiar tools:

  • Prettier with the slidev plugin keeps your slides consistently formatted
  • ESLint validates code snippets before you present
  • Obsidian works as an alternative editor (I created the obsidian-slidev plugin for this)

Prettier configuration (optional but recommended):

export default {
  plugins: ["prettier-plugin-slidev"],
  overrides: [
    {
      files: ["slides.md", "pages/*.md"],
      options: {
        parser: "slidev",
        plugins: ["prettier-plugin-slidev"],
      },
    },
    {
      files: "*.svg",
      options: {
        parser: "html",
      },
    },
  ],
};

Slide Fundamentals

Slides use standard Markdown syntax with --- as separators. Control each slide’s appearance with frontmatter:

---
layout: center
class: text-center pb-5
---

# Your Slide Title

Content goes here

Pro tip: Use HTML for precise positioning when needed, but stick to Markdown for readability and maintenance.

Content Creation

Layouts for Every Purpose

Slidev includes professional built-in layouts that handle common presentation patterns:

  • cover - Eye-catching title slides
  • center - Centered content for impact
  • image-right - Visual explanations with images
  • intro - Speaker introductions
  • section - Clear section breaks
  • two-columns-header - Side-by-side comparisons

View the source code to understand how they work.

Custom Layouts

Need something specific? Create Vue components in your layouts/ folder. For example, here’s a modified two-column layout with adjustable gap:

---
layout: two-cols-header-gap
---

# Side-by-side code and result

::left::

```tsx
export default function App() {
  return (
    <Canvas>
      <ambientLight />
      <mesh>
        <boxGeometry />
        <meshStandardMaterial />
      </mesh>
    </Canvas>
  );
}
```

::right::

<BrowserWrapper>
  <DemoIframe url="/demo/basic" />
</BrowserWrapper>
```

Start by copying existing layouts from Slidev’s GitHub and modify to fit your needs.

Styling with UnoCSS

Slidev uses UnoCSS, which means you can apply Tailwind-style utility classes directly to any element. This gives you pixel-perfect control without leaving your Markdown:

<div class="text-2xl font-bold text-blue-500">
  Styled text
</div>

Code Presentation

Code is often the star of technical presentations. Slidev makes it shine.

Syntax Highlighting

Wrap code in triple backticks with the language name for automatic highlighting:

```ts
function divide(a: number, b: number) {
  return a / b;
}
```

Progressive Line Highlighting

Guide your audience’s attention by highlighting specific lines. Add metadata after the language name:

```ts {all|1|2,4|3|2-4|all}
function divide(a: number, b: number) {
  return a / b;
}
```

Quick Reference:

  • {all} - Highlight everything
  • {1} - First line only
  • {2-4} - Lines 2 through 4
  • {1,3,5} - Specific lines
  • {all|1|2-3} - Click through these steps

Each section separated by | represents a new click step during your presentation.

TypeScript Type Hints with Twoslash

Show your audience exactly what types TypeScript infers. Use ts twoslash to display inline type information and catch errors:

```ts twoslash
function divide(a: number, b: number) {
  return a / b;
}
// ---cut-before---
const result = divide("hi", 2);
```

The ^? annotation shows type information, while // ---cut-before--- hides setup code from the audience but keeps it for type checking.

twoslash-error

twoslash-hint

Magic Move for Code Transformations

When demonstrating refactoring or showing how code evolves, Magic Move creates smooth transitions between code states. Use four backticks with md magic-move:

````md magic-move
```ts
async function program() {
  const data = await fetchData();
  const parsed = parseData(data);
  return saveData(parsed);
}
```

```ts
const program = Effect.gen(function* () {
  const data = yield* fetchData();
  const parsed = yield* parseData(data);
  return yield* saveData(parsed);
});
```
````

This shines when showing code refactoring, demonstrating how one pattern evolves into another, or explaining step-by-step improvements.

magic-move

Live Code with Monaco Editor

Let your audience experiment with code during your presentation. Slidev embeds the Monaco editor (VSCode’s editor) with live execution using monaco-run:

---
monacoRunAdditionalDeps:
  - ollama
---

```js {monaco-run}
import ollama from "ollama/browser";

const response = await ollama.chat({
  model: "llama3",
  messages: [{ role: "user", content: "Why is the sky blue?" }],
  stream: true,
});
for await (const part of response) {
  console.log(part.message.content);
}
```

Note: This requires network access and appropriate dependencies. Test thoroughly before presenting offline.

Interactivity

Progressive Disclosure with v-click

Build suspense and control pacing by revealing elements one at a time:

<div v-click>Appears on first click</div>
<div v-click="[2]">Appears on second click</div>

<v-clicks>
  - First bullet point
  - Second bullet point
  - Third bullet point
</v-clicks>

This keeps audiences focused on your current point rather than reading ahead.

Flexible Positioning with v-drag

Need to adjust element placement on the fly? The v-drag directive makes elements draggable and resizable during development. Double-click to adjust, and your changes save directly to the Markdown file:

<div v-drag class="absolute">
  Drag me anywhere
</div>

Smooth Animations with v-motion

Add professional polish with Vue Motion animations that respond to clicks:

<div
  v-motion
  v-click
  :initial="{ x: -80 }"
  :enter="{ x: 0, y: 0 }"
  class="border-teal bg-teal/10 absolute top-5 left-14"
  :click-1="{ y: 75, height: 130 }"
  :click-3="{ y: 205, height: 160 }"
/>

This creates dynamic diagrams that reveal themselves step-by-step, perfect for explaining complex concepts.

Slide Transitions

Control how slides transition with built-in effects: fade-out, fade, slide-up, view-transition, or none:

---
transition: fade-out
---

Choose transitions that match your presentation’s tone - subtle for professional talks, dynamic for engaging workshops.

Presentation Mode

Speaker Notes That Actually Help

Keep your talking points organized with HTML comments that only you see:

<!--
Explain the problem we're solving
[click]
Show how this pattern solves it
[click]
Mention the performance implications
-->

The [click] markers automatically highlight and scroll to the next section of your speaker notes when you advance slides, keeping you perfectly in sync.

speaker notes

Powerful Speaker View Features

The speaker view isn’t just about notes:

  • Cursor synchronization between speaker display and projected slides
  • Drawing tools that auto-save for reuse in future presentations
  • Visual adjustments for hue, contrast, and brightness to adapt to different venues
  • Next slide preview so you’re never caught off guard

speaker-view-and-slide drawings tweeks

Recording Presentations

Create video presentations with camera overlay - perfect for virtual conferences, recorded tutorials, or practice sessions. Slidev handles the technical setup so you can focus on presenting.

Slides Overview Mode

Press o during your presentation for a bird’s-eye view of all slides. This isn’t just for navigation - you can edit slides directly from overview mode, making last-minute adjustments effortless.

overview-r3f.png overview-edit

Advanced Customization

Reusable Components

Create Vue components in the components/ folder to encapsulate common functionality. For example, a QR code component:

<!-- components/QrCode.vue -->
<script setup lang="ts">
import { renderSVG } from "uqr";
import { computed } from "vue";

const props = defineProps<{
  text: string;
  white?: string;
  black?: string;
}>();

const html = computed(() =>
  renderSVG(props.text, {
    whiteColor: props.white,
    blackColor: props.black,
  }),
);
</script>

<template>
  <div v-html="html" />
</template>

Use in any slide:

<QrCode text="https://myslides.com" />

React Components

Need React instead of Vue? The slidev-addon-react addon lets you embed React components. Create components in react-components/ and use them:

<React is="MyComponent" prop="value" />

Custom Syntax with Preparers

Advanced feature: Create custom Markdown syntax for your specific needs. For example, I built a @@@ syntax block that renders multiple code files in an interactive Sandpack editor. The FilesPlayground component is a custom React component I created using Sandpack that displays multiple code files with tabs.

Create setup/preparser.ts and define your transformation:

const SANDPACK_BLOCK_REGEX =
  /@@@\s*\n((?:```tsx sandpack[^\n]*\n[\s\S]*?\n```\s*)+)@@@/g;

export default definePreparserSetup(() => {
  return [
    {
      name: "sandpack @@@",
      async transformSlide(content) {
        return content.replaceAll(SANDPACK_BLOCK_REGEX, transformSandpackBlock);
      },
    },
  ];
});

function transformSandpackBlock(match: string, blocksContent: string): string {
  const files = mergeByIndex(extractFilesFromBlocks(blocksContent));
  const filesJson = JSON.stringify(files).replaceAll('"', "&quot;");
  return `<React is="FilesPlayground" :files="${filesJson}"></React>`;
}

Usage in slides:

@@@

```tsx sandpack index=0
import { OrbitControls } from "@react-three/drei";
import { Canvas } from "@react-three/fiber";

export default function App() {
  return (
    <Canvas>
      <OrbitControls />
      <mesh>
        <boxGeometry args={[1, 1, 1]} />
        <meshMatcapMaterial color={"#0066CC"} />
      </mesh>
    </Canvas>
  );
}
```

```tsx sandpack index=1
import { OrbitControls } from "@react-three/drei";
import { Canvas } from "@react-three/fiber";

export default function App() {
  return (
    <Canvas>
      <OrbitControls />
      <axesHelper />
      <mesh position={[0, 0, 0]} scale={[1, 1, 1]} rotation={[0, 0, 0]}>
        <boxGeometry args={[1, 1, 1]} />
        <meshMatcapMaterial color={"#0066CC"} />
      </mesh>
    </Canvas>
  );
}
```

```tsx sandpack index=2 file="App.tsx"
import { OrbitControls } from "@react-three/drei";
import { Canvas } from "@react-three/fiber";
import { Box } from "./Box";

export default function App() {
  return (
    <Canvas>
      <OrbitControls />
      <Box position={[-1.2, 0, 0]} />
      <Box position={[1.2, 0, 0]} />
    </Canvas>
  );
}
```

```tsx sandpack index=2 file="Box.tsx"
import { useState } from "react";
import type { ThreeElements } from "@react-three/fiber";

export function Box(props: ThreeElements["mesh"]) {
  const [hovered, setHover] = useState(false);
  const [active, setActive] = useState(false);

  return (
    <mesh
      {...props}
      scale={active ? 1.5 : 1}
      onClick={() => setActive(!active)}
      onPointerOver={() => setHover(true)}
      onPointerOut={() => setHover(false)}
    >
      <boxGeometry args={[1, 1, 1]} />
      <meshMatcapMaterial color={hovered ? "#0066CC" : "#FF5733"} />
    </mesh>
  );
}
```

@@@

custom-sandpack sandpack-files

Note: This is advanced functionality. Most users won’t need it, but if you’re building a presentation toolkit for your team or have unique requirements, it enables powerful customization. Learn more about preparers and transformers in the docs.

Global Styling

Create src/global-top.vue for styles that apply to all slides:

<style>
.slidev-runner-output {
  overflow: auto;
  max-height: 200px;
}

code {
  --prism-font-size: 16px;
}

.slidev-code {
  --slidev-code-font-size: 16px;
  --slidev-code-line-height: 20px;
}

.slidev-react-container {
  width: 100%;
  height: 100%;
}
</style>

Use global-top.vue or global-bottom.vue to add headers, footers, or animated elements that persist across slides. Antfu uses this technique for smooth animated backgrounds that transition between slides.

Embedding Live Demos

Integrate live examples or documentation directly into your slides:

<iframe src="https://example.com" width="100%" height="400"></iframe>

Video Demonstrations

Include video walkthroughs or screen recordings:

<SlidevVideo controls>
  <source src="/demo.mp4" type="video/mp4" />
</SlidevVideo>

Deployment & Sharing

Exporting

Generate multiple formats from a single source:

# Export speaker notes
slidev export-notes

# Create PDFs (one per slide or combined)
slidev export --per-slide --output presentation.pdf

# Generate PowerPoint files
slidev export --format pptx

Hosting

You can deploy to any static hosting service, including GitHub Pages, Netlify, Vercel, or any other static host. Once deployed, your presentations are available as shareable URLs that work on any device.

Ecosystem

Extend Slidev with community addons:

Search npm for slidev-addon-* to discover more.

Conclusion

Slidev empowers developers to create presentations that are as dynamic and precise as the code they explain. By treating slides as code, you gain version control, reusable components, and the ability to embed actual running code in your presentations.

With AI tools becoming more prevalent, they can now assist in creating these presentations, helping you write content, generate code examples, or even suggest slide layouts. Start with pnpm create slidev - the default template comes packed with features demonstrating what’s possible. You can pick and choose what works for your presentation style and gradually incorporate more advanced techniques as you become comfortable with the tool.

For developers seeking a modern presentation tool that truly understands code, Slidev is unmatched.