Creating Slidev Presentations
Slidev is a web-based slide maker designed for developers. Write slides in Markdown, leverage Vue 3 components, and export to PDF, PPTX, or PNG. Ideal for technical presentations, demos, and interactive content.
Quick Start
Create a New Project
npm init slidev
# or
pnpm create slidev
Basic Commands
npm run dev # Start development server (http://localhost:5173)
npm run build # Build as static site
npm run export # Export to PDF, PPTX, or PNG
npm run format # Format slides.md
Slidev Markdown Structure
File Organization
- slides.md - Main presentation file (default)
- public/ - Static assets (images, files)
- package.json - Dependencies and scripts
Slide Separators
Use --- with blank lines to separate slides:
---
layout: cover
---
# Title Slide
---
# Content Slide
Frontmatter Configuration
Headmatter (First Slide)
Configure the entire presentation in the first slide's frontmatter:
---
theme: default
title: My Presentation
info: Presentation description
author: Your Name
highlighter: shiki
lineNumbers: true
mdc: true
css: unocss
shiki:
theme: nord
layout: cover
---
Per-Slide Frontmatter
Configure individual slides:
---
layout: two-cols
background: url('/bg.jpg')
clicks: 3
transition: slide-left
---
Key Frontmatter Options
| Option | Values | Purpose |
|---|---|---|
theme |
default, dark, custom theme |
Presentation theme |
layout |
cover, default, two-cols, image-right, center |
Slide layout |
background |
URL or color (#0D1117) | Slide background |
transition |
slide-left, fade, none |
Slide transition animation |
clicks |
Number | Animation click steps |
hideInToc |
Boolean | Hide from table of contents |
disabled |
Boolean | Skip slide in export |
preload |
Boolean | Preload before navigation |
Markdown Features
Code Blocks with Syntax Highlighting
\`\`\`typescript async function agent() { const skills = await Skill.all(); }
\`\`\`
\`\`\`python {1,3}
# Line 1 highlighted
print("not highlighted") print("highlighted") \`\`\`
Scoped CSS
Add styles to specific slides:
<style scoped>
h1 {
color: #58A6FF;
}
</style>
Vue Components
Use Vue 3 components in slides:
<script setup>
import { ref } from 'vue'
const count = ref(0)
</script>
<template>
<button @click="count++">
Count: {{ count }}
</button>
</template>
Presenter Notes
Add notes visible only to presenter:
---
layout: cover
---
# Title Slide
<!-- This is a presenter note, not shown to audience -->
Common Layouts
Cover Slide
---
layout: cover
---
# My Presentation
Title + Content
---
layout: default
---
# Section Title
- Bullet point 1
- Bullet point 2
Two Columns
---
layout: two-cols
---
::left::
# Left Column
Content
::right::
# Right Column
Content
Image Right
---
layout: image-right
image: /path/to/image.png
---
# Title
Content on left, image on right
Center Layout
---
layout: center
---
# Centered Content
Styling Slides
Inline Styles
<div style="color: #58a6ff; font-size: 24px">
Styled text
</div>
CSS Classes
<div class="text-blue-500 text-xl font-bold">
Styled with UnoCSS
</div>
Global Styles
Add to headmatter <style> block:
---
## ...
<style>
.slidev-layout {
background: #0D1117 !important;
}
h1 {
color: #F8FAFC !important;
}
</style>
Advanced Features
Diagrams with Mermaid
\`\`\`mermaid graph LR A[Start] --> B[Process] --> C[End] \`\`\`
LaTeX Math
$$
E = mc^2
$$
Inline: $\alpha = \frac{\beta}{\gamma}$
Animations & Clicks
---
clicks: 3
---
# Title
<v-click>This appears on click 1</v-click>
<v-click>This appears on click 2</v-click>
Draggable Elements
<div v-drag="'id-key'" style="position: absolute;">
Drag me around
</div>
Exporting Presentations
Export to PDF
npm run export -- --format pdf
npm run export -- --format pdf --output my-slides.pdf
Export to PPTX
npm run export -- --format pptx
# All slides exported as images for compatibility
Export to PNG
npm run export -- --format png
# Creates PNG for each slide in dist/
Export with Animations
npm run export -- --format pdf --with-clicks
# Exports multiple pages per slide with animation steps
Export Options
# Specific slide range
npm run export -- --range 1,3-5,10
# Dark mode
npm run export -- --dark
# Increase timeout for large presentations
npm run export -- --timeout 60000
# Add table of contents
npm run export -- --with-toc
Configuration File (slidev.config.ts)
Create slidev.config.ts for advanced configuration:
import { defineConfig } from "@slidev/cli";
export default defineConfig({
// Enable/disable features
monaco: true,
twoslash: true,
recorder: true,
// Export settings
export: {
format: "pdf",
timeout: 30000,
dark: false,
},
// Theme configuration
themeConfig: {
primary: "#5d8392",
},
});
Best Practices
Content Organization
- Keep headmatter clean and focused
- Use descriptive slide titles
- One idea per slide
- Limit bullet points to 3-5 per slide
Code in Presentations
- Use syntax highlighting with language specification
- Highlight important lines with
{1,3} - Show complete, runnable examples
- Explain code before revealing it with
<v-click>
Styling
- Use consistent color scheme
- Define global styles in headmatter
- Use scoped styles for slide-specific customization
- Test dark mode for exports
Interactive Elements
- Use Vue components for dynamic content
- Add click animations for complex topics
- Include live code examples with Monaco editor
- Record demos when presenting remotely
Accessibility
- Use semantic HTML elements
- Ensure sufficient color contrast
- Provide alt text for images
- Test with screen readers
Common Issues
Blank First Page
Ensure headmatter is properly formatted and includes layout: cover if needed.
First --- marks headmatter start, second --- marks headmatter end.
Code Block Rendering Issues
- Verify language is specified:
```typescript - Ensure blank lines around code blocks
- Use proper escaping for special characters
Export Failures
- Install Playwright:
npm install -D playwright-chromium - Use modern Chromium browser
- Increase timeout for large presentations
- Check for missing fonts or images
Styling Not Applied
- Use
!importantfor global overrides - Scope CSS with
<style scoped> - Check CSS specificity
- Clear browser cache
Resources
- Official Docs: https://sli.dev
- GitHub: https://github.com/slidevjs/slidev
- Discord: https://chat.sli.dev
- Examples: https://sli.dev/resources/theme-gallery
Integration with Development Workflow
Version Control
- Commit
slides.mdto git - Ignore
dist/,node_modules/,.git-pptx/ - Use
.gitignore:dist/ node_modules/ *.pdf *.pptx *.png
CI/CD Export
# GitHub Actions example
- name: Export slides to PDF
run: npx slidev export --format pdf
Embedding in Web Projects
Build as static site and host:
npm run build
# Deploy dist/ folder to web server
Example: Technical Presentation Template
---
theme: default
background: "#0D1117"
title: Agent Skills Integration
author: Your Name
highlighter: shiki
layout: cover
---
<style>
.slidev-layout {
background: #0D1117 !important;
}
h1, h2, h3 {
color: #F8FAFC !important;
}
p, li {
color: #E2E8F0 !important;
}
</style>
# Agent Skills Integration
Building reusable skill components
---
# Overview
- Skill definition and structure
- Automatic discovery
- System prompt injection
- Tool registration
---
# Implementation
\`\`\`typescript export function createSkillTool(skills: SkillInfo[]) { return
tool({ description: 'Load a skill', execute: async ({ name }) => { return await
Skill.load(name); }, }); } \`\`\`
---
layout: center
---
# Questions?
Workflow for Creating Professional Presentations
- Plan: Outline content and structure
- Draft: Write slides.md with basic content
- Style: Add CSS, themes, and layout configuration
- Animate: Add interactions and animations
- Test: Preview in browser, test exports
- Export: Generate PDF/PPTX for distribution
- Present: Use Slidev dev server with presenter mode
FAQ - Common Pitfalls & Solutions
Blank First Page Issue
Problem: First slide appears blank even with content defined.
Root Cause:
- Empty space between headmatter closing
---and content - Headmatter not properly containing opening content
- Missing
layoutconfiguration in headmatter
Solution:
---
theme: default
title: My Presentation
layout: cover
---
# Title Content Starts Here Immediately
No blank lines between --- and content!
Key Points:
- Headmatter must have
layout: coverfor first slide to display properly - Content starts immediately after closing
--- - Do NOT have blank lines between
---and#heading - The first slide content is part of the headmatter, not a separate slide
Markdown Code Blocks in HTML Containers
Problem: Code blocks don't render when nested inside HTML <div> elements.
<!-- ❌ WRONG -->
<div class="code-container">
<div class="code-content">
```markdown
const x = 1;
```markdown const x = 1; ```
Root Cause: Slidev's markdown parser requires blank lines around code blocks, even inside HTML.
Solution:
- Add blank line BEFORE opening backticks
- Add blank line AFTER closing backticks
- Indent appropriately for readability
Code Block Background Colors Not Working
Problem: Global <style> color overrides for code blocks are ignored.
Root Cause: Shiki syntax highlighter applies inline styles with higher specificity, and MDC/Vue markdown rendering creates additional nested elements.
Solution: Use !important in CSS rules:
<style>
.code-content {
padding: 16px 20px;
background: #0F172A !important;
color: #F1F5F9;
}
.code-content pre {
background: #0F172A !important;
}
.code-content code {
background: #0F172A !important;
color: #F1F5F9 !important;
}
</style>
Headings Appear Black in Dark Theme
Problem: <h1>, <h2>, <h3> tags render in black despite global style
definitions.
Root Cause:
- Default theme styles have high specificity
- Vue component scoping interferes with global selectors
- CSS classes generated by Slidev override simple selectors
Solution: Define heading styles in headmatter <style> block with multiple
selector specificity:
<style>
/* Use both bare selectors AND .slidev-layout selectors */
h1, h2, h3 {
color: #F8FAFC !important;
}
.slidev-layout h1 {
color: #F8FAFC !important;
}
.slidev-layout h2 {
color: #F8FAFC !important;
}
.slidev-layout h3 {
color: #F8FAFC !important;
}
</style>
Inconsistent Styling Across Multiple Slides
Problem: Some slides have correct styling, others appear broken (wrong background, missing colors).
Root Cause: Individual slides not inheriting global frontmatter
configuration. Each slide using src: import needs its own frontmatter.
Solution: Either:
- Merge all slides into single file (Recommended for small presentations):
---
theme: default
background: "#0D1117"
layout: cover
---
<style>
/* Global styles here */
</style>
# First Slide
---
# Second Slide
---
# Third Slide
- Or add frontmatter to each external slide file:
---
background: "#0D1117"
---
# Slide Content
Using src: Import Creates Empty Blank Slide
Problem: Using src: ./slides/01-cover.md in frontmatter creates an
unwanted blank page.
Root Cause: Slidev treats src: import as a slide reference within the
frontmatter, creating a slide separator.
Solution: Don't use src: in headmatter. Merge all content into single
slides.md file:
<!-- ❌ WRONG --> ---
## theme: default src: ./slides/01-cover.md
<!-- ✅ CORRECT --> ---
## theme: default
<style>
/* styles */
</style>
# Content here
---
# Next slide
Font/Color Changes Not Visible
Problem: CSS color definitions work locally but fail in exports (PDF/PPTX).
Root Cause:
- Browser uses fallback fonts in export
- CSS specificity issues in print context
- Missing
!importantflags
Solution:
<style>
/* Always use !important for export compatibility */
h1 {
color: #F8FAFC !important;
}
p {
color: #E2E8F0 !important;
}
code {
background: #1E293B !important;
color: #38BDF8 !important;
}
</style>
Export Command Not Found
Problem: slidev export command fails or not recognized.
Root Cause: @slidev/cli not installed or playwright-chromium missing.
Solution:
# Install/reinstall dependencies
npm install
# Install playwright for export
npm install -D playwright-chromium
# Try export again
npm run export -- --format pdf
Special Characters in Code Blocks Break Rendering
Problem: Angle brackets <>, curly braces {} in code blocks cause parsing
errors or display issues.
Root Cause: Vue/MDC markdown parser treats these as component syntax.
Solution: In inline code within markdown content, use HTML entities:
<→<>→>{→{}→}
Generate `<available_skills>` XML list
<!-- For code blocks, this usually isn't needed -->
\`\`\`typescript const xml = `<skill>data</skill>`; \`\`\`
Scoped Styles Not Applying
Problem: <style scoped> block doesn't affect slide elements.
Root Cause: Vue scoping requires scoped attribute AND proper element
hierarchy.
Solution:
---
layout: default
---
<style scoped>
/* Scoped styles only affect direct children of this slide */
h2 {
color: #58A6FF;
}
.custom-class {
font-weight: bold;
}
</style>
# Title
<div class="custom-class">Affected by scoped style</div>
Images Not Loading in Presentation
Problem: Images referenced in slides don't display.
Root Cause: Incorrect path references. Slidev serves static assets from
public/ folder.
Solution:
<!-- ❌ WRONG -->
<img src="./images/pic.png">
<!-- ✅ CORRECT -->
<img src="/images/pic.png">
<!-- Even simpler for images in public/ root -->
<img src="/pic.png">
<!-- Markdown image syntax also works -->

Store images in public/ folder at project root.
Large Presentations Take Forever to Export
Problem: slidev export takes many minutes or times out.
Root Cause: Complex layouts, large code blocks, or too many animations requiring render time.
Solution:
# Increase timeout (in milliseconds)
npm run export -- --format pdf --timeout 60000
# Add wait time between slides
npm run export -- --format pdf --wait 1000
# Export specific slide range for testing
npm run export -- --range 1-5
# Omit animations to speed up rendering
npm run export -- --format pdf --with-clicks false
Presenter Notes Not Showing
Problem: HTML comments added as presenter notes don't appear in presenter view.
Root Cause: Notes must be placed at the END of the slide, not at the beginning.
Solution:
---
layout: default
---
# Slide Title
Visible content here.
<!-- This is NOT a note - too early -->
More content.
<!-- This IS a presenter note - at the end of slide -->
Notes appear in the Slidev UI presenter panel when you click the presentation.
Line Highlighting in Code Blocks Not Working
Problem: Line number ranges like {1,3} don't highlight specified lines.
Root Cause:
- Language not specified for code block
- Syntax:
{1,3}must immediately follow backticks and language - Shiki highlighter requires proper configuration
Solution:
<!-- ✅ CORRECT -->
\`\`\`typescript {1,3} const a = 1; // Line 1 - highlighted const b = 2; // Line
2 - normal const c = 3; // Line 3 - highlighted \`\`\`
<!-- ❌ WRONG - no language or space before braces -->
\`\`\` {1,3} const a = 1; \`\`\`
Theme Not Applying Globally
Problem: Changing theme: in headmatter has no effect.
Root Cause: Theme must be specified BEFORE other configuration. Some configurations override theme defaults.
Solution:
---
# THEME MUST BE FIRST
theme: default
# Then other config
title: My Presentation
background: '#0D1117'
# Per-slide overrides at the end
layout: cover
---
If using custom theme, ensure it's installed:
npm install @slidev/theme-myname
Then:
---
theme: myname
---
Scripts
scripts/export-pdf.sh
Export presentation to PDF for sharing.
Usage:
bash scripts/export-pdf.sh
This script:
- Checks if dependencies are installed
- Runs
npm run exportto generate PDF - Outputs to
slides.pdf
Source: mcpc-tech/mcpc — distributed by TomeVault.