## Features
- 📝 [**Markdown-based**](https://sli.dev/guide/syntax) - focus on content and use your favorite editor
- 🧑💻 [**Developer Friendly**](https://sli.dev/guide/syntax#code-blocks) - built-in code highlighting, live coding, etc.
- 🎨 [**Themable**](https://sli.dev/resources/theme-gallery) - theme can be shared and used with npm packages
- 🌈 [**Stylish**](https://sli.dev/guide/syntax#embedded-styles) - on-demand utilities via [UnoCSS](https://github.com/unocss/unocss).
- 🤹 [**Interactive**](https://sli.dev/custom/directory-structure#components) - embedding Vue components seamlessly
- 🎙 [**Presenter Mode**](https://sli.dev/guide/ui#presenter-mode) - use another window, or even your phone to control your slides
- 🎨 [**Drawing**](https://sli.dev/features/drawing) - draw and annotate on your slides
- 🧮 [**LaTeX**](https://sli.dev/features/latex) - built-in LaTeX math equations support
- 📰 [**Diagrams**](https://sli.dev/guide/syntax#diagrams) - creates diagrams using textual descriptions with [Mermaid](https://mermaid.js.org/)
- 🌟 [**Icons**](https://sli.dev/features/icons) - access to icons from any icon set directly
- 💻 [**Editor**](https://sli.dev/guide/index#editor) - integrated editor, or the [VSCode extension](https://sli.dev/features/vscode-extension)
- 🎥 [**Recording**](https://sli.dev/features/recording) - built-in recording and camera view
- 📤 [**Portable**](https://sli.dev/guide/exporting) - export into PDF, PNGs, or PPTX
- ⚡️ [**Fast**](https://vitejs.dev) - instant reloading powered by [Vite](https://vitejs.dev)
- 🛠 [**Hackable**](https://sli.dev/custom/) - using Vite plugins, Vue components, or any npm packages
## Getting Started
### Try it Online ⚡️
[sli.dev/new](https://sli.dev/new)
[](https://sli.dev/new)
### Init Project Locally
Install [Node.js >=18](https://nodejs.org/) and run the following command:
```bash
npm init slidev
```
Documentation:
**[English](https://sli.dev)** | [中文文档](https://cn.sli.dev) | [Français](https://fr.sli.dev) | [Español](https://es.sli.dev) | [Русский](https://ru.sli.dev) | [Português-BR](https://br.sli.dev)
Discord: [chat.sli.dev](https://chat.sli.dev)
For a full example, you can check the [demo](https://github.com/slidevjs/slidev/blob/main/demo) folder, which is also the source file for [my previous talk](https://antfu.me/posts/composable-vue-vueday-2021).
## Tech Stack
- [Vite](https://vitejs.dev) - An extremely fast frontend tooling
- [Vue 3](https://v3.vuejs.org/) powered [Markdown](https://daringfireball.net/projects/markdown/syntax) - Focus on the content while having the power of HTML and Vue components whenever needed
- [UnoCSS](https://github.com/unocss/unocss) - On-demand utility-first CSS engine, style your slides at ease
- [Shiki](https://github.com/shikijs/shiki), [Monaco Editor](https://github.com/Microsoft/monaco-editor) - First-class code snippets support with live coding capability
- [RecordRTC](https://recordrtc.org) - Built-in recording and camera view
- [VueUse](https://vueuse.org) family - [`@vueuse/core`](https://github.com/vueuse/vueuse), [`@vueuse/motion`](https://github.com/vueuse/motion), etc.
- [Iconify](https://iconify.design/) - Icon sets collection.
- [Drauu](https://github.com/antfu/drauu) - Drawing and annotations support
- [KaTeX](https://katex.org/) - LaTeX math rendering.
- [Mermaid](https://mermaid-js.github.io/mermaid) - Textual Diagrams.
## Sponsors
This project is made possible by all the sponsors supporting my work:
` should have a green border, but no red text
---
src: sub/page1.md
---
This will be ignored
---
src: sub/page2.md
background: https://sli.dev/demo-cover.png
---
---
# Page 5
```html
{{$slidev.nav.currentPage}}
```
Current Page: {{$slidev.nav.currentPage}}
---
# Page 6
- A
- B
- C
1. C
2. B
3. A
---
# Page 7
$$
\begin{aligned}
\frac{D \boldsymbol{v}}{D t}=&-\frac{1}{\rho} \operatorname{grad} p+\frac{\mu}{\rho} \Delta \boldsymbol{v}+\frac{\lambda+\mu}{\rho} \operatorname{grad} \Theta+\frac{\Theta}{\rho} \operatorname{grad}(\lambda+\mu) \\
&+\frac{1}{\rho} \operatorname{grad}(\boldsymbol{v} \cdot \operatorname{grad} \mu)+\frac{1}{\rho} \operatorname{rot}(\boldsymbol{v} \times \operatorname{grad} \mu)-\frac{1}{\rho} \boldsymbol{v} \Delta \mu+\boldsymbol{g}
\end{aligned}
$$
---
layout: two-cols
---
::right::
# Right
Right
:: default ::
# Left
Left
---
# Page 9
A
B
C
D
E
---
# Page 10
A
B
C
D
---
# Page 11
- A
- B
- C
- D
- E
- F
- G
- H
- I
- J
- K
- L
---
# Page 12
A
B
A
B
- A
- B
---
# Page 13
E
F
(the next is kept for a future patch but not animating the nesting)
step i
step j
================================================
FILE: cypress/fixtures/basic/sub/page1.md
================================================
# Sub page 1
$x+2$
================================================
FILE: cypress/fixtures/basic/sub/page2.md
================================================
---
layout: cover
---
# Sub page 2
================================================
FILE: cypress/fixtures/basic/vite.config.ts
================================================
import { defineConfig } from 'vite'
export default defineConfig({
build: {
manifest: true,
minify: false,
},
})
================================================
FILE: cypress/tsconfig.json
================================================
{
"extends": "../tsconfig.json",
"compilerOptions": {
"types": ["cypress"],
"noEmit": true
},
"include": [
"../node_modules/cypress",
"./**/*.ts"
]
}
================================================
FILE: cypress.config.ts
================================================
import { defineConfig } from 'cypress'
export default defineConfig({
e2e: {
baseUrl: 'http://localhost:3041',
chromeWebSecurity: false,
specPattern: 'cypress/e2e/**/*.spec.*',
supportFile: false,
},
})
================================================
FILE: demo/README.md
================================================
The best way of understanding Slidev is to try it, with the following command:
```bash
npm init slidev
```
Learn more: https://sli.dev
================================================
FILE: demo/composable-vue/components/Connections.vue
================================================
### Pros
- Auto unwrapping (a.k.a `.value` free)
### Cons
- Same as plain objects on types
- Destructure loses reactivity
- Need to use callback for `watch`
---
# Ref Auto Unwrapping
Get rid of `.value` for most of the time.
- `watch` accepts ref as the watch target, and returns the unwrapped value in the callback
```ts
const counter = ref(0)
watch(counter, (count) => {
console.log(count) // same as `counter.value`
})
```
- Ref is auto unwrapped in the template
```html
```
- Reactive will auto-unwrap nested refs.
---
# Think as "Connections"
The `setup()` only runs **once** on component initialization, to construct the relations between your state and logic.
- Input → OutputEffects
- Output reflects to input's changes automatically
SpreadSheet Formula
---
# One Thing at a Time
Just the same as authoring JavaScript functions.
- Extract duplicated logics into composable functions
- Have meaningful names
- Consistent naming conversions - `useXX` `createXX` `onXX`
- Keep function small and simple
- "Do one thing, and do it well"
---
# Passing Refs as Arguments
### Implementation
### Usage
Plain function
```ts
function add(a: number, b: number) {
return a + b
}
```
```ts
const a = 1
const b = 2
const c = add(a, b) // 3
```
Accepts refs,
returns a reactive result.
```ts
function add(a: Ref, b: Ref) {
return computed(() => a.value + b.value)
}
```
```ts
const a = ref(1)
const b = ref(2)
const c = add(a, b)
c.value // 3
```
---
# MaybeRef
A custom type helper
```ts
type MaybeRef = Ref | T
```
In VueUse, we use this helper heavily to support optional reactive arguments
```ts
export function useTimeAgo(
time: Date | number | string | Ref,
) {
return computed(() => someFormating(unref(time)))
}
```
```ts {monaco}
import type { Ref } from 'vue'
import { computed, unref } from 'vue'
type MaybeRef = Ref | T
export function useTimeAgo(
time: MaybeRef,
) {
return computed(() => someFormating(unref(time)))
}
```
---
# Make it Flexible
Make your functions like LEGO, can be used with different components in different ways.
### Create a "Special" Ref
```ts {monaco}
import { useTitle } from '@vueuse/core'
const title = useTitle()
title.value = 'Hello World'
// now the page's title changed
```
### Binding an Existing Ref
```ts {monaco}
import { useTitle } from '@vueuse/core'
import { computed, ref } from 'vue'
const name = ref('Hello')
const title = computed(() => {
return `${name.value} - World`
})
useTitle(title) // Hello - World
name.value = 'Hi' // Hi - World
```
---
# `useTitle` Case
Take a look at `useTitle`'s implementation
```ts {monaco}
import type { MaybeRef } from '@vueuse/core'
import { ref, watch } from 'vue'
export function useTitle(
newTitle: MaybeRef,
) {
const title = ref(newTitle || document.title)
watch(title, (t) => {
if (t != null)
document.title = t
}, { immediate: true })
return title
}
```
```html
<-- 1. use the user provided ref or create a new one
<-- 2. sync ref changes to the document title
```
---
# "Reuse" Ref
If you pass a `ref` into `ref()`, it will return the original ref as-is.
```ts
const foo = ref(1) // Ref<1>
const bar = ref(foo) // Ref<1>
foo === bar // true
```
```ts
function useFoo(foo: Ref | string) {
// no need!
const bar = isRef(foo) ? foo : ref(foo)
// they are the same
const bar = ref(foo)
/* ... */
}
```
Extremely useful in composable functions that take uncertain argument types.
---
# `ref` / `unref`
- `MaybeRef` works well with `ref` and `unref`.
- Use `ref()` when you want to normalized it as a Ref.
- Use `unref()` when you want to have the value.
```ts
type MaybeRef = Ref | T
function useBala(arg: MaybeRef) {
const reference = ref(arg) // get the ref
const value = unref(arg) // get the value
}
```
---
# Object of Refs
Getting benefits from both `ref` and `reactive` for authoring composable functions
---
# Side-effects Self Cleanup
The `watch` and `computed` will stop themselves on components unmounted.
We'd recommend following the same pattern for your custom composable functions.
---
# `effectScope` RFC Upcoming
A new API to collect the side effects automatically. Likely to be shipped with Vue 3.1
https://github.com/vuejs/rfcs/pull/212
```ts
// effect, computed, watch, watchEffect created inside the scope will be collected
const scope = effectScope(() => {
const doubled = computed(() => counter.value * 2)
watch(doubled, () => console.log(double.value))
watchEffect(() => console.log('Count: ', double.value))
})
// dispose all effects in the scope
stop(scope)
```
---
disabled: true
---
# Template Ref
To get DOM element, you can pass a ref to it, and it will be available after component mounted
```ts {monaco}
import { defineComponent, onMounted, ref } from 'vue'
export default defineComponent({
setup() {
const element = ref()
onMounted(() => {
element.value // now you have it
})
return { element }
},
})
```
```html {monaco}
```
---
disabled: true
---
# Template Ref
Use `watch` instead of `onMounted` to unify the handling for template ref changes.
```ts {monaco}
import { defineComponent, ref, watch } from 'vue'
export default defineComponent({
setup() {
const element = ref()
watch(element, (el) => {
// clean up previous side effect
if (el) {
// use the DOM element
}
})
return { element }
},
})
```
---
# Typed Provide / Inject
Use the `InjectionKey` helper from Vue to share types across context.
```ts {monaco}
// context.ts
import type { InjectionKey } from 'vue'
export interface UserInfo {
id: number
name: string
}
export const injectKeyUser: InjectionKey = Symbol('user')
```
---
# Typed Provide / Inject
Import the key from the same module for `provide` and `inject`.
```ts {monaco}
// parent.vue
import { provide } from 'vue'
import { injectKeyUser } from './context'
export default {
setup() {
provide(injectKeyUser, {
id: '7', // type error: should be number
name: 'Anthony',
})
},
}
```
```ts {monaco}
// child.vue
import { inject } from 'vue'
import { injectKeyUser } from './context'
export default {
setup() {
const user = inject(injectKeyUser)
// UserInfo | undefined
if (user)
console.log(user.name) // Anthony
},
}
```
---
# Shared State
By the nature of Composition API, states can be created and used independently.
```ts
// shared.ts
import { reactive } from 'vue'
export const state = reactive({
foo: 1,
bar: 'Hello',
})
```
```ts
// A.vue
import { state } from './shared.ts'
state.foo += 1
```
```ts
// B.vue
import { state } from './shared.ts'
console.log(state.foo) // 2
```
⚠️ But it's not SSR compatible!
---
# Shared State (SSR friendly)
Use `provide` and `inject` to share the app-level state
```ts
export default defineComponent({
setup(props) {
const value = useVModel(props, 'value')
return { value }
},
})
```
```html
```
---
disabled: true
---
# useVModel (Passive)
Make the model able to be updated **independently** from the parent logic
```ts
export function usePassiveVModel(props, name) {
const emit = getCurrentInstance().emit
const data = ref(props[name]) // store the value in a ref
watch(() => props.value, v => data.value = v) // sync the ref whenever the prop changes
return computed({
get() {
return data.value
},
set(v) {
data.value = v // when setting value, update the ref directly
emit(`update:${name}`, v) // then emit out the changes
},
})
}
```
---
layout: center
---
# All of them work for both Vue 2 and 3
---
# `@vue/composition-api` Lib
Composition API support for Vue 2. [vuejs/composition-api](https://github.com/vuejs/composition-api)
```ts
import VueCompositionAPI from '@vue/composition-api'
import Vue from 'vue'
Vue.use(VueCompositionAPI)
```
```ts
import { reactive, ref } from '@vue/composition-api'
```
---
# Vue 2.7 Upcoming
[Plans in Vue 2.7](https://github.com/vuejs/rfcs/blob/ie11/active-rfcs/0000-vue3-ie11-support.md#for-those-who-absolutely-need-ie11-support)
- Backport `@vue/composition-api` into Vue 2's core.
- `
{{ counter }}
================================================
FILE: demo/starter/package.json
================================================
{
"name": "slidev-demo",
"private": true,
"scripts": {
"build": "slidev build",
"dev": "nodemon -w '../../packages/slidev/dist/*.mjs' --exec \"slidev ./slides.md --open=false --log=info --inspect\"",
"export": "slidev export",
"export-notes": "slidev export-notes"
},
"devDependencies": {
"@slidev/cli": "workspace:*",
"@slidev/theme-default": "catalog:themes",
"@slidev/theme-seriph": "catalog:themes",
"nodemon": "catalog:dev",
"vue": "catalog:frontend"
}
}
================================================
FILE: demo/starter/pages/imported-slides.md
================================================
# Imported Slides
You can split your slides.md into multiple files and organize them as you want using the `src` attribute.
#### `slides.md`
```markdown
# Page 1
Page 2 from main entry.
---
## src: ./subpage.md
```
#### `subpage.md`
```markdown
# Page 2
Page 2 from another file.
```
[Learn more](https://sli.dev/guide/syntax.html#importing-slides)
================================================
FILE: demo/starter/slides.md
================================================
---
# try also 'default' to start simple
theme: seriph
# random image from a curated Unsplash collection by Anthony
# like them? see https://unsplash.com/collections/94734566/slidev
background: https://cover.sli.dev
# some information about your slides (markdown enabled)
title: Welcome to Slidev
info: |
## Slidev Starter Template
Presentation slides for developers.
Learn more at [Sli.dev](https://sli.dev)
# apply UnoCSS classes to the current slide
class: text-center
# https://sli.dev/features/drawing
drawings:
persist: false
# slide transition: https://sli.dev/guide/animations.html#slide-transitions
transition: slide-left
# enable Comark Syntax: https://comark.dev/syntax/markdown
comark: true
# duration of the presentation
duration: 35min
---
# Welcome to Slidev
Presentation slides for developers
Press Space for next page
---
transition: fade-out
---
# What is Slidev?
Slidev is a slides maker and presenter designed for developers, consist of the following features
- 📝 **Text-based** - focus on the content with Markdown, and then style them later
- 🎨 **Themable** - themes can be shared and re-used as npm packages
- 🧑💻 **Developer Friendly** - code highlighting, live coding with autocompletion
- 🤹 **Interactive** - embed Vue components to enhance your expressions
- 🎥 **Recording** - built-in recording and camera view
- 📤 **Portable** - export to PDF, PPTX, PNGs, or even a hostable SPA
- 🛠 **Hackable** - virtually anything that's possible on a webpage is possible in Slidev
Read more about [Why Slidev?](https://sli.dev/guide/why)
---
transition: slide-up
level: 2
---
# Navigation
Hover on the bottom-left corner to see the navigation's controls panel, [learn more](https://sli.dev/guide/ui#navigation-bar)
## Keyboard Shortcuts
| | |
| --------------------------------------------------- | --------------------------- |
| right / space | next animation or slide |
| left / shiftspace | previous animation or slide |
| up | previous slide |
| down | next slide |
Here!
---
layout: two-cols
layoutClass: gap-16
---
# Table of contents
You can use the `Toc` component to generate a table of contents for your slides:
```html
```
The title will be inferred from your slide content, or you can override it with `title` and `level` in your frontmatter.
::right::
---
layout: image-right
image: https://cover.sli.dev
---
# Code
Use code snippets and get the highlighting directly, and even types hover!
```ts [filename-example.ts] {all|4|6|6-7|9|all} twoslash
// TwoSlash enables TypeScript hover information
// and errors in markdown code blocks
// More at https://shiki.style/packages/twoslash
import { computed, ref } from 'vue'
const count = ref(0)
const doubled = computed(() => count.value * 2)
doubled.value = 2
```
<<< @/snippets/external.ts#snippet
[Learn more](https://sli.dev/features/line-highlighting)
---
level: 2
---
# Shiki Magic Move
Powered by [shiki-magic-move](https://shiki-magic-move.netlify.app/), Slidev supports animations across multiple code snippets.
Add multiple code blocks and wrap them with ````md magic-move (four backticks) to enable the magic move. For example:
````md magic-move {lines: true}
```ts {*|2|*}
// step 1
const author = reactive({
name: 'John Doe',
books: [
'Vue 2 - Advanced Guide',
'Vue 3 - Basic Guide',
'Vue 4 - The Mystery'
]
})
```
```ts {*|1-2|3-4|3-4,8}
// step 2
export default {
data() {
return {
author: {
name: 'John Doe',
books: [
'Vue 2 - Advanced Guide',
'Vue 3 - Basic Guide',
'Vue 4 - The Mystery'
]
}
}
}
}
```
```ts
// step 3
export default {
data: () => ({
author: {
name: 'John Doe',
books: [
'Vue 2 - Advanced Guide',
'Vue 3 - Basic Guide',
'Vue 4 - The Mystery'
]
}
})
}
```
Non-code blocks are ignored.
```vue
```
````
---
# Components
You can use Vue components directly inside your slides.
We have provided a few built-in components like `` and `` that you can use directly. And adding your custom components is also super easy.
```html
```
Check out [the guides](https://sli.dev/builtin/components.html) for more.
```html
```
---
class: px-20
---
# Themes
Slidev comes with powerful theming support. Themes can provide styles, layouts, components, or even configurations for tools. Switching between themes by just **one edit** in your frontmatter:
Read more about [How to use a theme](https://sli.dev/guide/theme-addon#use-theme) and
check out the [Awesome Themes Gallery](https://sli.dev/resources/theme-gallery).
---
# Clicks Animations
You can add `v-click` to elements to add a click animation.
This shows up when you click the slide:
```html
This shows up when you click the slide.
```
The v-mark directive
also allows you to add
inline marks
, powered by [Rough Notation](https://roughnotation.com/):
```html
inline markers
```
---
# $\LaTeX$
$\LaTeX$ is supported out-of-box. Powered by [$\KaTeX$](https://katex.org/).
Inline $\sqrt{3x-1}+(1+x)^2$
Block
$$ {1|3|all}
\begin{aligned}
\nabla \cdot \vec{E} &= \frac{\rho}{\varepsilon_0} \\
\nabla \cdot \vec{B} &= 0 \\
\nabla \times \vec{E} &= -\frac{\partial\vec{B}}{\partial t} \\
\nabla \times \vec{B} &= \mu_0\vec{J} + \mu_0\varepsilon_0\frac{\partial\vec{E}}{\partial t}
\end{aligned}
$$
[Learn more](https://sli.dev/features/latex)
---
# Diagrams
You can create diagrams / graphs from textual descriptions, directly in your Markdown.
```mermaid {scale: 0.5, alt: 'A simple sequence diagram'}
sequenceDiagram
Alice->John: Hello John, how are you?
Note over Alice,John: A typical interaction
```
```mermaid {theme: 'neutral', scale: 0.8}
graph TD
B[Text] --> C{Decision}
C -->|One| D[Result 1]
C -->|Two| E[Result 2]
```
```mermaid
mindmap
root((mindmap))
Origins
Long history
::icon(fa fa-book)
Popularisation
British popular psychology author Tony Buzan
Research
On effectiveness and features
On Automatic creation
Uses
Creative techniques
Strategic planning
Argument mapping
Tools
Pen and paper
Mermaid
```
```plantuml {scale: 0.7}
@startuml
package "Some Group" {
HTTP - [First Component]
[Another Component]
}
node "Other Groups" {
FTP - [Second Component]
[First Component] --> FTP
}
cloud {
[Example 1]
}
database "MySql" {
folder "This is my folder" {
[Folder 3]
}
frame "Foo" {
[Frame 4]
}
}
[Another Component] --> [Example 1]
[Example 1] --> [Folder 3]
[Folder 3] --> [Frame 4]
@enduml
```
Learn more: [Mermaid Diagrams](https://sli.dev/features/mermaid) and [PlantUML Diagrams](https://sli.dev/features/plantuml)
---
foo: bar
dragPos:
square: 691,32,167,_,-16
---
# Draggable Elements
Double-click on the draggable elements to edit their positions.
###### Directive Usage
```md
```
###### Component Usage
```md
Use the `v-drag` component to have a draggable container!
```
Double-click me!
###### Draggable Arrow
```md
```
---
src: ./pages/imported-slides.md
hide: false
---
---
# Monaco Editor
Slidev provides built-in Monaco Editor support.
Add `{monaco}` to the code block to turn it into an editor:
```ts {monaco}
import { ref } from 'vue'
import { emptyArray } from './external'
const arr = ref(emptyArray(10))
```
Use `{monaco-run}` to create an editor that can execute the code directly in the slide:
```ts {monaco-run}
import { version } from 'vue'
import { emptyArray, sayHello } from './external'
sayHello()
console.log(`vue ${version}`)
console.log(emptyArray(10).reduce(fib => [...fib, fib.at(-1)! + fib.at(-2)!], [1, 1]))
```
---
layout: center
class: text-center
---
# Learn More
[Documentation](https://sli.dev) · [GitHub](https://github.com/slidevjs/slidev) · [Showcases](https://sli.dev/resources/showcases)
================================================
FILE: demo/starter/snippets/external.ts
================================================
/* eslint-disable no-console */
// #region snippet
// Inside ./snippets/external.ts
export function emptyArray(length: number) {
return Array.from({ length })
}
// #endregion snippet
export function sayHello() {
console.log('Hello from snippets/external.ts')
}
================================================
FILE: demo/starter/style.css
================================================
/* add any global style here */
================================================
FILE: demo/starter/vite.config.ts
================================================
import { defineConfig } from 'vite'
export default defineConfig({
plugins: [],
})
================================================
FILE: demo/vue-runner/package.json
================================================
{
"private": true,
"scripts": {
"build": "slidev build",
"dev": "nodemon -w '../../packages/slidev/dist/*.mjs' --exec \"slidev ./slides.md --open=false --log=info --inspect\"",
"export": "slidev export",
"export-notes": "slidev export-notes"
},
"devDependencies": {
"@slidev/cli": "workspace:*",
"@slidev/theme-default": "catalog:themes",
"@slidev/theme-seriph": "catalog:themes",
"@vue/compiler-sfc": "catalog:demo",
"nodemon": "catalog:dev",
"vue": "catalog:frontend"
}
}
================================================
FILE: demo/vue-runner/setup/code-runners.ts
================================================
/* eslint-disable no-new-func */
import { defineCodeRunnersSetup } from '@slidev/types'
export default defineCodeRunnersSetup(() => {
return {
// Support Vue SFC
async vue(code) {
const Vue = await import('vue')
const { parse, compileScript } = await import('@vue/compiler-sfc')
// Compile the script, note this demo does not handle Vue styles
const sfc = parse(code)
let scripts = compileScript(sfc.descriptor, {
id: sfc.descriptor.filename,
genDefaultAs: '__Component',
inlineTemplate: true,
}).content
// Replace Vue imports to object destructuring
// Only for simple demo, it doesn't work with imports from other packages
scripts = scripts.replace(/import (\{[^}]+\}) from ['"]vue['"]/g, (_, imports) => `const ${imports.replace(/\sas\s/g, ':')} = Vue`)
scripts += '\nreturn __Component'
// Create function to evaluate the script and get the component
// Note this is not sandboxed, it's NOT secure.
const component = new Function(`return (Vue) => {${scripts}}`)()(Vue)
// Mount the component
const app = Vue.createApp(component)
const el = document.createElement('div')
app.mount(el)
return {
element: el,
}
},
}
})
================================================
FILE: demo/vue-runner/setup/shiki.ts
================================================
import type { ShikiSetupReturn } from '@slidev/types'
import { defineShikiSetup } from '@slidev/types'
export default defineShikiSetup((): ShikiSetupReturn => {
return {
langs: [
'ts',
'js',
'vue',
'html',
],
}
})
================================================
FILE: demo/vue-runner/slides.md
================================================
---
layout: default
---
# Simple Vue SFC Runner
```vue {monaco-run}
================================================
FILE: docs/.vitepress/theme/components/Environment.vue
================================================
Environment:
{{ type }}
This setup function will run on both Node.js and client side. Avoid using Node.js or DOM API to prevent runtime errors.
This setup function will only run on Node.js environment, you can have access to Node's API.
This setup function will only run on client side. Make sure the browser compatibility when importing packages.
================================================
FILE: docs/.vitepress/theme/composables/dark.ts
================================================
import { useDark } from '@vueuse/core'
export const isDark = useDark()
================================================
FILE: docs/.vitepress/theme/index.ts
================================================
import type { EnhanceAppContext } from 'vitepress'
import TwoSlash from '@shikijs/vitepress-twoslash/client'
import Theme from 'vitepress/theme'
import Layout from './components/Layout.vue'
import '@shikijs/vitepress-twoslash/style.css'
import './styles/vars.css'
import './styles/demo.css'
import './styles/custom.css'
import 'uno.css'
import 'virtual:group-icons.css'
export default {
extends: Theme,
enhanceApp({ app }: EnhanceAppContext) {
app.use(TwoSlash as any)
},
Layout,
}
================================================
FILE: docs/.vitepress/theme/styles/custom.css
================================================
.icon-btn {
--uno: inline-block cursor-pointer select-none important-outline-none;
--uno: opacity-75 transition duration-200 ease-in-out align-middle rounded p-2;
--uno: hover-(opacity-100 bg-gray-400 bg-opacity-10);
}
.icon-btn.disabled {
--uno: opacity-25 pointer-events-none;
}
.inline-icon-btn {
--uno: text-primary-deep;
--uno: inline-block rounded p-0.5 text-2xl align-middle;
--uno: border border-primary border-opacity-20 border-solid;
}
kbd {
--uno: border-rounded bg-$vp-c-gray-1 bg-opacity-10 px-1 py-.5;
}
[data-tweet-id] {
border-radius: 13px;
}
================================================
FILE: docs/.vitepress/theme/styles/demo.css
================================================
html:not(.dark) {
--prism-foreground: #393a34;
--prism-background: #fafafa;
--prism-inline-background: #f5f5f5;
--prism-comment: #a0ada0;
--prism-string: #b56959;
--prism-literal: #2f8a89;
--prism-number: #296aa3;
--prism-keyword: #1c6b48;
--prism-function: #6c7834;
--prism-boolean: #296aa3;
--prism-constant: #a65e2b;
--prism-deleted: #a14f55;
--prism-class: #2993a3;
--prism-builtin: #ab5959;
--prism-property: #b58451;
--prism-namespace: #b05a78;
--prism-punctuation: #8e8f8b;
--prism-decorator: #bd8f8f;
--prism-regex: #ab5e3f;
--prism-json-property: #698c96;
}
html.dark {
--prism-scheme: dark;
--prism-foreground: #d4cfbf;
--prism-background: #181818;
--prism-comment: #758575;
--prism-string: #d48372;
--prism-literal: #429988;
--prism-keyword: #4d9375;
--prism-boolean: #6394bf;
--prism-number: #6394bf;
--prism-variable: #c2b36e;
--prism-function: #a1b567;
--prism-deleted: #bc6066;
--prism-class: #54b1bf;
--prism-builtin: #e0a569;
--prism-property: #dd8e6e;
--prism-namespace: #db889a;
--prism-punctuation: #858585;
--prism-decorator: #bd8f8f;
--prism-regex: #ab5e3f;
--prism-json-property: #6b8b9e;
--prism-line-number: #888888;
--prism-line-number-gutter: #eeeeee;
--prism-line-highlight-background: #444444;
--prism-selection-background: #444444;
--prism-inline-background: theme('colors.dark.300');
}
.token.title {
color: var(--prism-keyword);
}
.token.comment,
.token.prolog,
.token.doctype,
.token.cdata {
color: var(--prism-comment);
font-style: var(--prism-comment-style);
}
.token.namespace {
color: var(--prism-namespace);
}
.token.interpolation {
color: var(--prism-interpolation);
}
.token.string {
color: var(--prism-string);
}
.token.punctuation {
color: var(--prism-punctuation);
}
.token.operator {
color: var(--prism-operator);
}
.token.keyword.module,
.token.keyword.control-flow {
color: var(--prism-keyword-control);
}
.token.url,
.token.symbol,
.token.inserted {
color: var(--prism-symbol);
}
.token.constant {
color: var(--prism-constant);
}
.token.string.url {
text-decoration: var(--prism-url-decoration);
}
.token.boolean,
.language-json .token.boolean {
color: var(--prism-boolean);
}
.token.number,
.language-json .token.number {
color: var(--prism-number);
}
.token.variable {
color: var(--prism-variable);
}
.token.keyword {
color: var(--prism-keyword);
}
.token.atrule,
.token.attr-value,
.token.selector {
color: var(--prism-selector);
}
.token.function {
color: var(--prism-function);
}
.token.deleted {
color: var(--prism-deleted);
}
.token.important,
.token.bold {
font-weight: bold;
}
.token.italic {
font-style: italic;
}
.token.class-name {
color: var(--prism-class);
}
.token.tag,
.token.builtin {
color: var(--prism-builtin);
}
.token.attr-name,
.token.property,
.token.entity {
color: var(--prism-property);
}
.language-json .token.property {
color: var(--prism-json-property);
}
.token.regex {
color: var(--prism-regex);
}
.token.decorator,
.token.annotation {
color: var(--prism-decorator);
}
================================================
FILE: docs/.vitepress/theme/styles/vars.css
================================================
/**
* Customize default theme styling by overriding CSS variables:
* https://github.com/vuejs/vitepress/blob/main/src/client/theme-default/styles/vars.css
*/
/**
* Colors
*
* Each colors have exact same color scale system with 3 levels of solid
* colors with different brightness, and 1 soft color.
*
* - `XXX-1`: The most solid color used mainly for colored text. It must
* satisfy the contrast ratio against when used on top of `XXX-soft`.
*
* - `XXX-2`: The color used mainly for hover state of the button.
*
* - `XXX-3`: The color for solid background, such as bg color of the button.
* It must satisfy the contrast ratio with pure white (#ffffff) text on
* top of it.
*
* - `XXX-soft`: The color used for subtle background such as custom container
* or badges. It must satisfy the contrast ratio when putting `XXX-1` colors
* on top of it.
*
* The soft color must be semi transparent alpha channel. This is crucial
* because it allows adding multiple "soft" colors on top of each other
* to create a accent, such as when having inline code block inside
* custom containers.
*
* - `default`: The color used purely for subtle indication without any
* special meanings attched to it such as bg color for menu hover state.
*
* - `brand`: Used for primary brand colors, such as link text, button with
* brand theme, etc.
*
* - `tip`: Used to indicate useful information. The default theme uses the
* brand color for this by default.
*
* - `warning`: Used to indicate warning to the users. Used in custom
* container, badges, etc.
*
* - `danger`: Used to show error, or dangerous message to the users. Used
* in custom container, badges, etc.
* -------------------------------------------------------------------------- */
:root {
--vp-c-brand-1: #3ab9d4;
--vp-c-brand-2: #60c4db;
--vp-c-brand-3: #6fcce1;
--vp-c-brand-soft: #3ab9d450;
--vp-c-bg-alt: #f9f9f9;
--vp-font-family-mono: theme('fontFamily.mono');
}
.dark {
--vp-c-brand-1: #6fcce1;
--vp-c-brand-2: #60c4db;
--vp-c-brand-3: #3ab9d4;
--vp-c-brand-soft: #3ab9d450;
--vp-c-bg-alt: #18181b;
--vp-c-gutter: #8883;
}
:root {
--vp-c-default-1: var(--vp-c-gray-1);
--vp-c-default-2: var(--vp-c-gray-2);
--vp-c-default-3: var(--vp-c-gray-3);
--vp-c-default-soft: var(--vp-c-gray-soft);
--vp-c-tip-1: var(--vp-c-brand-1);
--vp-c-tip-2: var(--vp-c-brand-2);
--vp-c-tip-3: var(--vp-c-brand-3);
--vp-c-tip-soft: var(--vp-c-brand-soft);
}
:root {
-vp-c-text-1: rgba(42, 40, 47);
-vp-c-text-2: rgba(42, 40, 47, 0.78);
-vp-c-text-3: rgba(42, 40, 47, 0.56);
--black-text-1: rgba(42, 40, 47);
}
.dark {
--vp-c-text-1: rgba(255, 255, 245, 0.86);
--vp-c-text-2: rgba(235, 235, 245, 0.6);
--vp-c-text-3: rgba(235, 235, 245, 0.38);
}
/**
* Component: Button
* -------------------------------------------------------------------------- */
:root {
--vp-button-brand-border: transparent;
--vp-button-brand-text: var(--vp-c-white);
--vp-button-brand-bg: var(--vp-c-brand-1);
--vp-button-brand-hover-border: transparent;
--vp-button-brand-hover-text: var(--vp-c-white);
--vp-button-brand-hover-bg: var(--vp-c-brand-2);
--vp-button-brand-active-border: transparent;
--vp-button-brand-active-text: var(--vp-c-white);
--vp-button-brand-active-bg: var(--vp-c-brand-1);
}
.dark {
--vp-button-brand-text: var(--black-text-1);
--vp-button-brand-bg: var(--vp-c-brand-2);
--vp-button-brand-hover-text: var(--black-text-1);
--vp-button-brand-hover-bg: var(--vp-c-brand-1);
--vp-button-brand-active-text: var(--black-text-1);
--vp-button-brand-active-bg: var(--vp-c-brand-3);
}
/**
* Component: Home
* -------------------------------------------------------------------------- */
:root {
--vp-home-hero-name-color: var(--vp-c-brand-1);
}
@media (min-width: 640px) {
:root {
--vp-home-hero-image-filter: blur(56px);
}
}
@media (min-width: 960px) {
:root {
--vp-home-hero-image-filter: blur(72px);
}
}
/**
* Component: Custom Block
* -------------------------------------------------------------------------- */
:root {
--vp-custom-block-tip-border: transparent;
--vp-custom-block-tip-text: var(--vp-c-text-1);
--vp-custom-block-tip-bg: var(--vp-c-brand-soft);
--vp-custom-block-tip-code-bg: var(--vp-c-brand-soft);
}
/**
* Component: Algolia
* -------------------------------------------------------------------------- */
.DocSearch {
--docsearch-primary-color: var(--vp-c-brand-1) !important;
}
================================================
FILE: docs/.vitepress/themes.ts
================================================
export interface ThemeInfo {
id: string
name: string
description: string
previews: string[]
repo?: string
author: {
name: string
link?: string
}
link?: string
tags?: string[]
}
export const official: ThemeInfo[] = [
{
id: '@slidev/theme-default',
name: 'Default',
description: 'The minimalism default theme for Slidev',
author: {
name: 'Anthony Fu',
link: 'https://github.com/antfu',
},
repo: 'https://github.com/slidevjs/themes/tree/main/packages/theme-default',
previews: [
'https://cdn.jsdelivr.net/gh/slidevjs/themes@main/screenshots/theme-default/01.png',
'https://cdn.jsdelivr.net/gh/slidevjs/themes@main/screenshots/theme-default/02.png',
'https://cdn.jsdelivr.net/gh/slidevjs/themes@main/screenshots/theme-default/06.png',
'https://cdn.jsdelivr.net/gh/slidevjs/themes@main/screenshots/theme-default/08.png',
],
tags: [
'official',
'minimalism',
'dark',
'light',
],
},
{
id: '@slidev/theme-seriph',
name: 'Seriph',
description: 'A more formal looking theme using Serif fonts',
author: {
name: 'Anthony Fu',
link: 'https://github.com/antfu',
},
repo: 'https://github.com/slidevjs/themes/tree/main/packages/theme-seriph',
previews: [
'https://cdn.jsdelivr.net/gh/slidevjs/themes@main/screenshots/theme-seriph/01.png',
'https://cdn.jsdelivr.net/gh/slidevjs/themes@main/screenshots/theme-seriph/02.png',
'https://cdn.jsdelivr.net/gh/slidevjs/themes@main/screenshots/theme-seriph/03.png',
'https://cdn.jsdelivr.net/gh/slidevjs/themes@main/screenshots/theme-seriph/08.png',
],
tags: [
'official',
'minimalism',
'dark',
'light',
],
},
{
id: '@slidev/theme-apple-basic',
name: 'Apple Basic',
description: 'Inspired by the Basic Black/White theme from Apple Keynote',
author: {
name: 'Jeremy Meissner',
link: 'https://github.com/JeremyMeissner',
},
repo: 'https://github.com/slidevjs/themes/tree/main/packages/theme-apple-basic',
previews: [
'https://cdn.jsdelivr.net/gh/slidevjs/themes@main/screenshots/theme-apple-basic/01.png',
'https://cdn.jsdelivr.net/gh/slidevjs/themes@main/screenshots/theme-apple-basic/02.png',
'https://cdn.jsdelivr.net/gh/slidevjs/themes@main/screenshots/theme-apple-basic/03.png',
'https://cdn.jsdelivr.net/gh/slidevjs/themes@main/screenshots/theme-apple-basic/09.png',
'https://cdn.jsdelivr.net/gh/slidevjs/themes@main/screenshots/theme-apple-basic/11.png',
],
tags: [
'minimalism',
'dark',
'light',
],
},
{
id: '@slidev/theme-bricks',
name: 'Bricks',
description: 'Building bricks',
author: {
name: 'iiiiiiinès',
link: 'https://github.com/iiiiiiines',
},
repo: 'https://github.com/slidevjs/themes/tree/main/packages/theme-bricks',
previews: [
'https://cdn.jsdelivr.net/gh/slidevjs/themes@main/screenshots/theme-bricks/01.png',
'https://cdn.jsdelivr.net/gh/slidevjs/themes@main/screenshots/theme-bricks/04.png',
'https://cdn.jsdelivr.net/gh/slidevjs/themes@main/screenshots/theme-bricks/06.png',
'https://cdn.jsdelivr.net/gh/slidevjs/themes@main/screenshots/theme-bricks/05.png',
],
tags: [
'light',
],
},
{
id: '@slidev/theme-shibainu',
name: 'Shibainu',
description: 'Meow!',
author: {
name: 'iiiiiiinès',
link: 'https://github.com/iiiiiiines',
},
repo: 'https://github.com/slidevjs/themes/tree/main/packages/theme-shibainu',
previews: [
'https://cdn.jsdelivr.net/gh/slidevjs/themes@main/screenshots/theme-shibainu/01.png',
'https://cdn.jsdelivr.net/gh/slidevjs/themes@main/screenshots/theme-shibainu/03.png',
'https://cdn.jsdelivr.net/gh/slidevjs/themes@main/screenshots/theme-shibainu/04.png',
'https://cdn.jsdelivr.net/gh/slidevjs/themes@main/screenshots/theme-shibainu/09.png',
],
tags: [
'dark',
],
},
]
export const community: ThemeInfo[] = [
{
id: 'slidev-theme-geist',
name: 'Vercel',
description: 'A theme based on Vercel\'s design system.',
author: {
name: 'Nico Bachner',
link: 'https://github.com/nico-bachner',
},
repo: 'https://github.com/nico-bachner/slidev-theme-geist',
previews: [
'https://cdn.jsdelivr.net/gh/nico-bachner/slidev-theme-geist@main/example-export/01.png',
'https://cdn.jsdelivr.net/gh/nico-bachner/slidev-theme-geist@main/example-export/02.png',
'https://cdn.jsdelivr.net/gh/nico-bachner/slidev-theme-geist@main/example-export/03.png',
'https://cdn.jsdelivr.net/gh/nico-bachner/slidev-theme-geist@main/example-export/04.png',
'https://cdn.jsdelivr.net/gh/nico-bachner/slidev-theme-geist@main/example-export/05.png',
],
tags: [
'dark',
'light',
],
},
{
id: 'slidev-theme-light-icons',
name: 'Light Icons',
description: 'A simple, light and elegant theme for Slidev, combined together with creative layouts, custom components & fonts',
author: {
name: 'Pulkit Aggarwal',
link: 'https://github.com/BashCloud',
},
repo: 'https://github.com/lightvue/slidev-theme-light-icons',
previews: [
'https://cdn.jsdelivr.net/gh/lightvue/slidev-theme-light-icons@master/screenshot/1-layout-intro.png',
'https://cdn.jsdelivr.net/gh/lightvue/slidev-theme-light-icons@master/screenshot/2-layout-image-header-intro-light.png',
'https://cdn.jsdelivr.net/gh/lightvue/slidev-theme-light-icons@master/screenshot/3-layout-dynamic-image-light.png',
'https://cdn.jsdelivr.net/gh/lightvue/slidev-theme-light-icons@master/screenshot/5-layout-dynamic-image-light.png',
'https://cdn.jsdelivr.net/gh/lightvue/slidev-theme-light-icons@master/screenshot/7-layout-dynamic-image-light.png',
'https://cdn.jsdelivr.net/gh/lightvue/slidev-theme-light-icons@master/screenshot/8-layout-center-image-light.png',
'https://cdn.jsdelivr.net/gh/lightvue/slidev-theme-light-icons@master/screenshot/9-layout-dynamic-image-light.png',
'https://cdn.jsdelivr.net/gh/lightvue/slidev-theme-light-icons@master/screenshot/10-layout-left-image-light.png',
],
tags: [
'dark',
'light',
],
},
{
id: 'slidev-theme-eloc',
name: 'Eloc',
description: 'Focus on writing, present in a concise style.',
author: {
name: 'Amio',
link: 'https://github.com/amio',
},
repo: 'https://github.com/zthxxx/slides/tree/master/packages/slidev-theme-eloc',
previews: [
'https://cdn.jsdelivr.net/gh/zthxxx/slides@master/packages/slidev-theme-eloc/screenshot/01.png',
'https://cdn.jsdelivr.net/gh/zthxxx/slides@master/packages/slidev-theme-eloc/screenshot/02.png',
'https://cdn.jsdelivr.net/gh/zthxxx/slides@master/packages/slidev-theme-eloc/screenshot/03.png',
'https://cdn.jsdelivr.net/gh/zthxxx/slides@master/packages/slidev-theme-eloc/screenshot/04.png',
'https://cdn.jsdelivr.net/gh/zthxxx/slides@master/packages/slidev-theme-eloc/screenshot/05.png',
],
tags: [
'dark',
'light',
],
},
{
id: 'slidev-theme-purplin',
name: 'Purplin',
description: 'Theme with bar bottom component. Based on purple color',
author: {
name: 'Mauricio Martínez',
link: 'https://github.com/moudev',
},
repo: 'https://github.com/moudev/slidev-theme-purplin',
previews: [
'https://i.imgur.com/BX3TpEc.png',
'https://i.imgur.com/mqqRi1F.png',
'https://i.imgur.com/fwm2785.png',
'https://i.imgur.com/m8eemKt.png',
],
tags: [
'dark',
'light',
],
},
{
id: 'slidev-theme-unicorn',
name: 'Unicorn',
description: 'Based on Dawntraoz website design',
author: {
name: 'Alba Silvente',
link: 'https://github.com/dawntraoz',
},
repo: 'https://github.com/dawntraoz/slidev-theme-unicorn',
previews: [
'https://cdn.jsdelivr.net/gh/Dawntraoz/slidev-theme-unicorn@master/screenshots/dark-theme-intro.png',
'https://cdn.jsdelivr.net/gh/Dawntraoz/slidev-theme-unicorn@master/screenshots/light-theme-cover.png',
'https://cdn.jsdelivr.net/gh/Dawntraoz/slidev-theme-unicorn@master/screenshots/dark-theme-image-centered.png',
'https://cdn.jsdelivr.net/gh/Dawntraoz/slidev-theme-unicorn@master/screenshots/dark-theme-center-without-header-footer.png',
],
tags: [
'dark',
'light',
],
},
{
id: 'slidev-theme-zhozhoba',
name: 'Zhozhoba',
description: 'A zhozhoba theme for Slidev',
author: {
name: 'Bogenbai Bayzharassov',
link: 'https://github.com/thatoranzhevyy',
},
repo: 'https://github.com/thatoranzhevyy/slidev-theme-zhozhoba',
previews: [
'https://cdn.jsdelivr.net/gh/thatoranzhevyy/slidev-theme-zhozhoba@master/slides-export/01.png',
'https://cdn.jsdelivr.net/gh/thatoranzhevyy/slidev-theme-zhozhoba@master/.github/dark.png',
'https://cdn.jsdelivr.net/gh/thatoranzhevyy/slidev-theme-zhozhoba@master/slides-export/02.png',
'https://cdn.jsdelivr.net/gh/thatoranzhevyy/slidev-theme-zhozhoba@master/slides-export/03.png',
'https://cdn.jsdelivr.net/gh/thatoranzhevyy/slidev-theme-zhozhoba@master/slides-export/04.png',
],
tags: [
'dark',
'light',
],
},
{
id: 'slidev-theme-penguin',
name: 'Penguin',
description: 'A Penguin theme for Slidev',
author: {
name: 'Alvaro Saburido',
link: 'https://github.com/alvarosabu',
},
repo: 'https://github.com/alvarosabu/slidev-theme-penguin',
previews: [
'https://cdn.jsdelivr.net/gh/alvarosaburido/slidev-theme-penguin@master/screenshots/dark/01.png',
'https://cdn.jsdelivr.net/gh/alvarosaburido/slidev-theme-penguin@master/screenshots/light/02.png',
'https://cdn.jsdelivr.net/gh/alvarosaburido/slidev-theme-penguin@master/screenshots/light/06.png',
'https://cdn.jsdelivr.net/gh/alvarosaburido/slidev-theme-penguin@master/screenshots/light/05.png',
],
tags: [
'dark',
'light',
],
},
{
id: 'slidev-theme-vuetiful',
name: 'Vuetiful',
description: 'A Vue-inspired theme for Slidev',
author: {
name: 'Thorsten Lünborg',
link: 'https://github.com/LinusBorg',
},
repo: 'https://github.com/LinusBorg/slidev-theme-vuetiful',
previews: [
'https://cdn.jsdelivr.net/gh/LinusBorg/slidev-theme-vuetiful@main/screenshots/cover-alt.png',
'https://cdn.jsdelivr.net/gh/LinusBorg/slidev-theme-vuetiful@main/screenshots/section.png',
'https://cdn.jsdelivr.net/gh/LinusBorg/slidev-theme-vuetiful@main/screenshots/big-points.png',
'https://cdn.jsdelivr.net/gh/LinusBorg/slidev-theme-vuetiful@main/screenshots/quote.png',
],
tags: [
'dark',
'light',
],
},
{
id: 'slidev-theme-takahashi',
name: 'Takahashi',
description: 'A simple theme for Slidev',
author: {
name: 'Percy M.',
link: 'https://github.com/kecrily',
},
repo: 'https://github.com/kecrily/slidev-theme-takahashi',
previews: [
'https://cdn.jsdelivr.net/gh/kecrily/slidev-theme-takahashi@master/screenshots/01.png',
'https://cdn.jsdelivr.net/gh/kecrily/slidev-theme-takahashi@master/screenshots/02.png',
'https://cdn.jsdelivr.net/gh/kecrily/slidev-theme-takahashi@master/screenshots/03.png',
'https://cdn.jsdelivr.net/gh/kecrily/slidev-theme-takahashi@master/screenshots/04.png',
'https://cdn.jsdelivr.net/gh/kecrily/slidev-theme-takahashi@master/screenshots/05.png',
'https://cdn.jsdelivr.net/gh/kecrily/slidev-theme-takahashi@master/screenshots/06.png',
'https://cdn.jsdelivr.net/gh/kecrily/slidev-theme-takahashi@master/screenshots/07.png',
],
tags: [
'light',
],
},
{
id: 'slidev-theme-academic',
name: 'Academic',
description: 'Academic presentations with Slidev made simple',
author: {
name: 'Alexander Eble',
link: 'https://github.com/alexanderdavide',
},
repo: 'https://github.com/alexanderdavide/slidev-theme-academic',
previews: [
'https://cdn.jsdelivr.net/gh/alexanderdavide/slidev-theme-academic@assets/example-export/01.png',
'https://cdn.jsdelivr.net/gh/alexanderdavide/slidev-theme-academic@assets/example-export/02.png',
'https://cdn.jsdelivr.net/gh/alexanderdavide/slidev-theme-academic@assets/example-export/08.png',
'https://cdn.jsdelivr.net/gh/alexanderdavide/slidev-theme-academic@assets/example-export/04.png',
'https://cdn.jsdelivr.net/gh/alexanderdavide/slidev-theme-academic@assets/example-export/05.png',
'https://cdn.jsdelivr.net/gh/alexanderdavide/slidev-theme-academic@assets/example-export/06.png',
'https://cdn.jsdelivr.net/gh/alexanderdavide/slidev-theme-academic@assets/example-export/07.png',
],
tags: [
'dark',
'light',
],
},
{
id: 'slidev-theme-mokkapps',
name: 'Mokkapps',
description: 'A theme for my personal brand "Mokkapps"',
author: {
name: 'Michael Hoffmann',
link: 'https://github.com/mokkapps',
},
repo: 'https://github.com/mokkapps/slidev-theme-mokkapps',
previews: [
'https://cdn.jsdelivr.net/gh/mokkapps/slidev-theme-mokkapps@master/screenshots/dark/001.png',
'https://cdn.jsdelivr.net/gh/mokkapps/slidev-theme-mokkapps@master/screenshots/dark/002.png',
'https://cdn.jsdelivr.net/gh/mokkapps/slidev-theme-mokkapps@master/screenshots/dark/003.png',
'https://cdn.jsdelivr.net/gh/mokkapps/slidev-theme-mokkapps@master/screenshots/dark/004.png',
'https://cdn.jsdelivr.net/gh/mokkapps/slidev-theme-mokkapps@master/screenshots/dark/005.png',
'https://cdn.jsdelivr.net/gh/mokkapps/slidev-theme-mokkapps@master/screenshots/dark/006.png',
'https://cdn.jsdelivr.net/gh/mokkapps/slidev-theme-mokkapps@master/screenshots/dark/007.png',
'https://cdn.jsdelivr.net/gh/mokkapps/slidev-theme-mokkapps@master/screenshots/dark/008.png',
'https://cdn.jsdelivr.net/gh/mokkapps/slidev-theme-mokkapps@master/screenshots/dark/009.png',
'https://cdn.jsdelivr.net/gh/mokkapps/slidev-theme-mokkapps@master/screenshots/dark/010.png',
'https://cdn.jsdelivr.net/gh/mokkapps/slidev-theme-mokkapps@master/screenshots/dark/011.png',
],
tags: [
'dark',
'light',
],
},
{
id: 'slidev-theme-the-unnamed',
name: 'The unnamed',
description: 'A theme based on The unnamed VS Code theme',
author: {
name: 'Elio Struyf',
link: 'https://elio.dev',
},
repo: 'https://github.com/estruyf/slidev-theme-the-unnamed',
previews: [
'https://cdn.jsdelivr.net/gh/estruyf/slidev-theme-the-unnamed@main/assets/cover.png',
'https://cdn.jsdelivr.net/gh/estruyf/slidev-theme-the-unnamed@main/assets/about-me.png',
'https://cdn.jsdelivr.net/gh/estruyf/slidev-theme-the-unnamed@main/assets/default.png',
'https://cdn.jsdelivr.net/gh/estruyf/slidev-theme-the-unnamed@main/assets/section.png',
],
tags: [
'dark',
],
},
{
id: 'slidev-theme-dracula',
name: 'Dracula',
description: 'One the best dark theme meets slidev',
author: {
name: 'JD Solanki',
link: 'https://github.com/jd-solanki',
},
repo: 'https://github.com/jd-solanki/slidev-theme-dracula',
previews: [
'https://cdn.jsdelivr.net/gh/jd-solanki/slidev-theme-dracula/screenshots/screenshot-1.png',
'https://cdn.jsdelivr.net/gh/jd-solanki/slidev-theme-dracula/screenshots/screenshot-2.png',
'https://cdn.jsdelivr.net/gh/jd-solanki/slidev-theme-dracula/screenshots/screenshot-3.png',
'https://cdn.jsdelivr.net/gh/jd-solanki/slidev-theme-dracula/screenshots/screenshot-4.png',
'https://cdn.jsdelivr.net/gh/jd-solanki/slidev-theme-dracula/screenshots/screenshot-5.png',
],
tags: [
'dark',
'minimalism',
],
},
{
id: 'slidev-theme-frankfurt',
name: 'Frankfurt',
description: 'Inspired by the Beamer theme Frankfurt',
author: {
name: 'Mu-Tsun Tsai',
link: 'https://github.com/MuTsunTsai',
},
repo: 'https://github.com/MuTsunTsai/slidev-theme-frankfurt',
previews: [
'https://cdn.jsdelivr.net/gh/MuTsunTsai/slidev-theme-frankfurt/screenshots/01.png',
'https://cdn.jsdelivr.net/gh/MuTsunTsai/slidev-theme-frankfurt/screenshots/04.png',
'https://cdn.jsdelivr.net/gh/MuTsunTsai/slidev-theme-frankfurt/screenshots/06.png',
'https://cdn.jsdelivr.net/gh/MuTsunTsai/slidev-theme-frankfurt/screenshots/07.png',
],
tags: [
'dark',
'light',
],
},
{
id: 'slidev-theme-hep',
name: 'HEP',
description: 'Academic style for High Energy Physics',
author: {
name: 'Yulei ZHANG',
link: 'https://github.com/AvencastF',
},
repo: 'https://github.com/AvencastF/slidev-theme-hep',
previews: [
'https://cdn.jsdelivr.net/gh/avencastf/slidev-theme-hep/screenshot/001.png',
'https://cdn.jsdelivr.net/gh/avencastf/slidev-theme-hep/screenshot/004.png',
'https://cdn.jsdelivr.net/gh/avencastf/slidev-theme-hep/screenshot/006.png',
'https://cdn.jsdelivr.net/gh/avencastf/slidev-theme-hep/screenshot/008.png',
],
tags: [
'light',
],
},
{
id: 'slidev-theme-excali-slide',
name: 'Excali-slide',
description: 'A theme based on Excalidraw with animated highlighter effect',
author: {
name: 'Filip Hric',
link: 'https://github.com/filiphric',
},
repo: 'https://github.com/filiphric/slidev-theme-excali-slide',
previews: [
'https://raw.githubusercontent.com/filiphric/excali-slide/main/images/default_slide.png',
'https://raw.githubusercontent.com/filiphric/excali-slide/main/images/intro_slide.png',
],
tags: [
'dark',
'light',
],
},
{
id: 'slidev-theme-mint',
name: 'mint',
description: 'Slidev Theme Mint',
author: {
name: 'Alfatta Rezqa',
link: 'https://github.com/alfatta',
},
repo: 'https://github.com/alfatta/slidev-theme-mint',
previews: [
'https://cdn.jsdelivr.net/gh/alfatta/slidev-theme-mint/screenshot/1.png',
'https://cdn.jsdelivr.net/gh/alfatta/slidev-theme-mint/screenshot/2.png',
'https://cdn.jsdelivr.net/gh/alfatta/slidev-theme-mint/screenshot/3.png',
'https://cdn.jsdelivr.net/gh/alfatta/slidev-theme-mint/screenshot/4.png',
'https://cdn.jsdelivr.net/gh/alfatta/slidev-theme-mint/screenshot/5.png',
'https://cdn.jsdelivr.net/gh/alfatta/slidev-theme-mint/screenshot/6.png',
'https://cdn.jsdelivr.net/gh/alfatta/slidev-theme-mint/screenshot/7.png',
'https://cdn.jsdelivr.net/gh/alfatta/slidev-theme-mint/screenshot/8.png',
'https://cdn.jsdelivr.net/gh/alfatta/slidev-theme-mint/screenshot/9.png',
],
tags: [
'light',
'mint',
'green',
'cool',
],
},
{
id: 'slidev-theme-neversink',
name: 'neversink',
description: 'Slidev Theme Neversink',
author: {
name: 'Todd M. Gureckis',
link: 'https://github.com/gureckis',
},
repo: 'https://github.com/gureckis/slidev-theme-neversink',
previews: [
'https://gureckis.github.io/slidev-theme-neversink/screenshots/2.png',
'https://gureckis.github.io/slidev-theme-neversink/screenshots/6.png',
'https://gureckis.github.io/slidev-theme-neversink/screenshots/8.png',
'https://gureckis.github.io/slidev-theme-neversink/screenshots/15.png',
'https://gureckis.github.io/slidev-theme-neversink/screenshots/18.png',
'https://gureckis.github.io/slidev-theme-neversink/screenshots/22.png',
'https://gureckis.github.io/slidev-theme-neversink/screenshots/26.png',
'https://gureckis.github.io/slidev-theme-neversink/screenshots/34.png',
'https://gureckis.github.io/slidev-theme-neversink/screenshots/36.png',
'https://gureckis.github.io/slidev-theme-neversink/screenshots/38.png',
'https://gureckis.github.io/slidev-theme-neversink/screenshots/35.png',
],
tags: [
'light',
'academic',
'education',
],
},
{
id: 'slidev-theme-ktym4a',
name: 'ktym4a',
description: 'Based on ktym4a website design',
author: {
name: 'ktym4a',
link: 'https://github.com/ktym4a',
},
repo: 'https://github.com/ktym4a/slidev-theme-ktym4a',
previews: [
'https://cdn.jsdelivr.net/gh/ktym4a/slidev-theme-ktym4a@main/example-export/rotation/0.png',
'https://cdn.jsdelivr.net/gh/ktym4a/slidev-theme-ktym4a@main/example-export/rotation/1.png',
'https://cdn.jsdelivr.net/gh/ktym4a/slidev-theme-ktym4a@main/example-export/rotation/6.png',
'https://cdn.jsdelivr.net/gh/ktym4a/slidev-theme-ktym4a@main/example-export/rotation/7.png',
'https://cdn.jsdelivr.net/gh/ktym4a/slidev-theme-ktym4a@main/example-export/rotation/8.png',
'https://cdn.jsdelivr.net/gh/ktym4a/slidev-theme-ktym4a@main/example-export/single/0.png',
'https://cdn.jsdelivr.net/gh/ktym4a/slidev-theme-ktym4a@main/example-export/single/1.png',
'https://cdn.jsdelivr.net/gh/ktym4a/slidev-theme-ktym4a@main/example-export/single/3.png',
'https://cdn.jsdelivr.net/gh/ktym4a/slidev-theme-ktym4a@main/example-export/single/4.png',
],
tags: [
'dark',
'catppuccin',
],
},
{
id: 'slidev-theme-nord',
name: 'Nord',
description: 'Based on the Nord theme',
author: {
name: 'David Ollerhead',
link: 'https://github.com/oller',
},
repo: 'https://github.com/oller/slidev-theme-nord',
previews: [
'https://raw.githubusercontent.com/oller/slidev-theme-nord/HEAD/example-export/1.png',
'https://raw.githubusercontent.com/oller/slidev-theme-nord/HEAD/example-export/2.png',
'https://raw.githubusercontent.com/oller/slidev-theme-nord/HEAD/example-export/3.png',
'https://raw.githubusercontent.com/oller/slidev-theme-nord/HEAD/example-export/4.png',
'https://raw.githubusercontent.com/oller/slidev-theme-nord/HEAD/example-export/5.png',
'https://raw.githubusercontent.com/oller/slidev-theme-nord/HEAD/example-export/6.png',
'https://raw.githubusercontent.com/oller/slidev-theme-nord/HEAD/example-export/7.png',
],
tags: [
'dark',
'light',
'nord',
],
},
{
id: 'slidev-theme-scholarly',
name: 'Scholarly',
description: 'Based on the Nord theme',
author: {
name: 'Jiaxin Peng',
link: 'https://github.com/jxpeng98',
},
repo: 'https://github.com/jxpeng98/slidev-theme-scholarly',
previews: [
'https://raw.githubusercontent.com/jxpeng98/slidev-theme-scholarly/HEAD/images/themes/classic-blue/1.png',
'https://raw.githubusercontent.com/jxpeng98/slidev-theme-scholarly/HEAD/images/themes/oxford/1.png',
'https://raw.githubusercontent.com/jxpeng98/slidev-theme-scholarly/HEAD/images/themes/cambridge/1.png',
'https://raw.githubusercontent.com/jxpeng98/slidev-theme-scholarly/HEAD/images/themes/princeton/1.png',
'https://raw.githubusercontent.com/jxpeng98/slidev-theme-scholarly/HEAD/images/themes/classic-blue/2.png',
'https://raw.githubusercontent.com/jxpeng98/slidev-theme-scholarly/HEAD/images/themes/classic-blue/3.png',
'https://raw.githubusercontent.com/jxpeng98/slidev-theme-scholarly/HEAD/images/themes/classic-blue/4.png',
],
tags: [
'dark',
'light',
'academic',
'oxford',
'cambridge',
'princeton',
],
},
{
id: 'slidev-theme-field-manual',
name: 'Field Manual',
description: 'A 24-layout theme modeled on the style of vintage military field manuals',
author: {
name: 'PJ Doland',
link: 'https://github.com/pjdoland',
},
repo: 'https://github.com/pjdoland/slidev-theme-field-manual',
previews: [
'https://raw.githubusercontent.com/pjdoland/slidev-theme-field-manual/main/screenshots/1.jpg',
'https://raw.githubusercontent.com/pjdoland/slidev-theme-field-manual/main/screenshots/2.jpg',
'https://raw.githubusercontent.com/pjdoland/slidev-theme-field-manual/main/screenshots/3.jpg',
'https://raw.githubusercontent.com/pjdoland/slidev-theme-field-manual/main/screenshots/4.jpg',
'https://raw.githubusercontent.com/pjdoland/slidev-theme-field-manual/main/screenshots/5.jpg',
'https://raw.githubusercontent.com/pjdoland/slidev-theme-field-manual/main/screenshots/6.jpg',
'https://raw.githubusercontent.com/pjdoland/slidev-theme-field-manual/main/screenshots/7.jpg',
'https://raw.githubusercontent.com/pjdoland/slidev-theme-field-manual/main/screenshots/8.jpg',
'https://raw.githubusercontent.com/pjdoland/slidev-theme-field-manual/main/screenshots/9.jpg',
'https://raw.githubusercontent.com/pjdoland/slidev-theme-field-manual/main/screenshots/10.jpg',
'https://raw.githubusercontent.com/pjdoland/slidev-theme-field-manual/main/screenshots/11.jpg',
'https://raw.githubusercontent.com/pjdoland/slidev-theme-field-manual/main/screenshots/12.jpg',
'https://raw.githubusercontent.com/pjdoland/slidev-theme-field-manual/main/screenshots/13.jpg',
'https://raw.githubusercontent.com/pjdoland/slidev-theme-field-manual/main/screenshots/14.jpg',
'https://raw.githubusercontent.com/pjdoland/slidev-theme-field-manual/main/screenshots/15.jpg',
'https://raw.githubusercontent.com/pjdoland/slidev-theme-field-manual/main/screenshots/16.jpg',
'https://raw.githubusercontent.com/pjdoland/slidev-theme-field-manual/main/screenshots/17.jpg',
'https://raw.githubusercontent.com/pjdoland/slidev-theme-field-manual/main/screenshots/18.jpg',
'https://raw.githubusercontent.com/pjdoland/slidev-theme-field-manual/main/screenshots/19.jpg',
'https://raw.githubusercontent.com/pjdoland/slidev-theme-field-manual/main/screenshots/20.jpg',
'https://raw.githubusercontent.com/pjdoland/slidev-theme-field-manual/main/screenshots/21.jpg',
'https://raw.githubusercontent.com/pjdoland/slidev-theme-field-manual/main/screenshots/22.jpg',
'https://raw.githubusercontent.com/pjdoland/slidev-theme-field-manual/main/screenshots/23.jpg',
'https://raw.githubusercontent.com/pjdoland/slidev-theme-field-manual/main/screenshots/24.jpg',
'https://raw.githubusercontent.com/pjdoland/slidev-theme-field-manual/main/screenshots/25.jpg',
'https://raw.githubusercontent.com/pjdoland/slidev-theme-field-manual/main/screenshots/26.jpg',
'https://raw.githubusercontent.com/pjdoland/slidev-theme-field-manual/main/screenshots/27.jpg',
'https://raw.githubusercontent.com/pjdoland/slidev-theme-field-manual/main/screenshots/28.jpg',
'https://raw.githubusercontent.com/pjdoland/slidev-theme-field-manual/main/screenshots/29.jpg',
'https://raw.githubusercontent.com/pjdoland/slidev-theme-field-manual/main/screenshots/30.jpg',
'https://raw.githubusercontent.com/pjdoland/slidev-theme-field-manual/main/screenshots/31.jpg',
'https://raw.githubusercontent.com/pjdoland/slidev-theme-field-manual/main/screenshots/32.jpg',
'https://raw.githubusercontent.com/pjdoland/slidev-theme-field-manual/main/screenshots/33.jpg',
],
tags: [
'light',
'dark',
'vintage',
'military',
],
},
// Add yours here!
{
id: '',
link: 'https://github.com/slidevjs/slidev/edit/main/docs/.vitepress/themes.ts',
name: 'Yours?',
description: 'Click here to submit your theme :)',
author: {
name: '',
},
previews: [
'/theme-placeholder.png',
],
},
]
================================================
FILE: docs/.vitepress/utils.ts
================================================
import { data as features } from '../features/index.data.js'
import { Advanced, Guides } from './pages'
function removeHash(link: string) {
const idx = link.lastIndexOf('#')
return idx < 0 ? link : link.slice(0, idx)
}
function getGuideTitle(id: string) {
return Guides.find(g => g.link.endsWith(`/${id}`))?.text ?? Advanced.find(g => g.link.endsWith(id))?.text ?? id
}
export function resolveLink(link: string): {
kind: 'external' | 'features' | 'guide'
url: string
title?: string
tags?: string[]
descripton?: string
} {
const [kind, nameWithHash] = link.split('/')
const name = removeHash(nameWithHash)
switch (kind) {
case 'http:':
case 'https:':
case 'mailto:':
return { kind: 'external', url: link }
case 'features': {
const feature = features[name]
if (!feature)
throw new Error(`Feature "${name}" not found.`)
return {
kind: 'features',
title: `✨ ${feature.title}`,
tags: feature.tags,
descripton: feature.description,
url: `/features/${nameWithHash}`,
}
}
case 'guide': {
return {
kind: 'guide',
title: `📖 ${getGuideTitle(name)}`,
tags: ['guide'],
descripton: 'Click to read this guide',
url: `/guide/${nameWithHash}`,
}
}
default:
throw new Error(`Invalid link: ${link}`)
}
}
================================================
FILE: docs/README.md
================================================
# [sli.dev](https://sli.dev)
Documentation for [Slidev](https://github.com/slidevjs/slidev)
## Translations
> [!WARNING]
>
> Translations with strikethroughs are no longer maintained. The content is outdated and not encouraged to refer.
| | Repo | Site | Maintainers |
| ------------------------- | ---------------------------------------------- | -------------------------------: | --------------------------------------------------------------------- |
| English | [docs](https://github.com/slidevjs/docs) | [sli.dev](https://sli.dev) | [@antfu](https://github.com/antfu) |
| 简体中文 | [docs-cn](https://github.com/slidevjs/docs-cn) | [cn.sli.dev](https://cn.sli.dev) | [@QC-L](https://github.com/QC-L) [@Ivocin](https://github.com/Ivocin) |
| Français | [docs-fr](https://github.com/slidevjs/docs-fr) | [fr.sli.dev](https://fr.sli.dev) | [@ArthurDanjou](https://github.com/ArthurDanjou) |
| Español | [docs-es](https://github.com/slidevjs/docs-es) | [es.sli.dev](https://es.sli.dev) | [@owlnai](https://github.com/owlnai) |
| Русский | [docs-ru](https://github.com/slidevjs/docs-ru) | [ru.sli.dev](https://ru.sli.dev) | [@xesjkeee](https://github.com/xesjkeee) |
| Việt Nam | [docs-vn](https://github.com/slidevjs/docs-vn) | [vn.sli.dev](https://vn.sli.dev) | [@bongudth](https://github.com/bongudth) |
| Deutsch | [docs-de](https://github.com/slidevjs/docs-de) | [de.sli.dev](https://de.sli.dev) | [@fabiankachlock](https://github.com/fabiankachlock) |
| Português (BR) | [docs-br](https://github.com/slidevjs/docs-br) | [br.sli.dev](https://br.sli.dev) | [@luisfelipesdn12](https://github.com/luisfelipesdn12) |
| Ελληνικά | [docs-el](https://github.com/slidevjs/docs-el) | [el.sli.dev](https://el.sli.dev) | [@GeopJr](https://github.com/GeopJr) |
| 日本語 | [docs-ja](https://github.com/slidevjs/docs-ja) | [ja.sli.dev](https://ja.sli.dev) | [@IkumaTadokoro](https://github.com/IkumaTadokoro) |
## Start Server Locally
```
npm i -g pnpm
pnpm i
pnpm run dev
```
And then visit `http://localhost:3000`
Or install the [Vite extension for VS Code](https://marketplace.visualstudio.com/items?itemName=antfu.vite) to edit side-by-side.
## Help on Translating
Please join our [Discord Server](https://chat.sli.dev) and contact the maintainers.
================================================
FILE: docs/builtin/cli.md
================================================
# Slidev CLI
`@slidev/cli` exposes a binary called `slidev` that you can use to develop, build, and export your slides.
## Prerequisites
To use the CLI, you can either install `@slidev/cli` globally or install it locally in your Node.js project. If you created your project with `npm init slidev`, the CLI is already installed locally.
::: warning
Usually `npx slidev` is not supported because the package name is actually `@slidev/cli`.
:::
The CLI options of the commands obey the following conventions:
- the value of the option can be passed after a space or a `=` character:
Example: `slidev --port 8080` is equivalent to `slidev --port=8080`
- `true` can be omitted for boolean options:
Example: `slidev --open` is equivalent to `slidev --open true`
::: info
If you use npm, please don't forget to add `--` before the options to pass them to Slidev:
```bash
npm run slidev -- --remote --port 8080 --open
```
:::
## `slidev [entry]` {#dev}
Start a local server for Slidev.
- `[entry]` (`string`, default: `slides.md`): path to the markdown file containing your slides.
Options:
- `--port`, `-p` (`number`, default: `3030`): port number.
- `--base` (`string`, default: `/`): base URL (see https://vitejs.dev/config/shared-options.html#base).
- `--open`, `-o` (`boolean`, default: `false`): open in the browser.
- `--remote [password]` (`string`): listen to the public host and enable remote control, if a value is passed then the presenter mode is private and only accessible by passing the given password in the URL query `password` parameter.
- `--bind` (`string`, default: `0.0.0.0`): specify which IP addresses the server should listen on in the remote mode.
- `--log` (`'error', 'warn', 'info', 'silent'`, default: `'warn'`): Log level.
- `--force`, `-f` (`boolean`, default: `false`): force the optimizer to ignore the cache and re-bundle.
- `--theme`, `-t` (`string`): override theme.
## `slidev build [entry]` {#build}
Build a hostable SPA. See for more details.
- `[entry]` (`string`, default: `slides.md`): path to the slides markdown file.
Options:
- `--out`, `-o` (`string`, default: `dist`): output directory
- `--base` (`string`, default: `/`): base URL (see https://vitejs.dev/config/shared-options.html#base)
- `--download` (`boolean`, default: `false`): allow the download of the slides as a PDF inside the SPA
- `--theme`, `-t` (`string`): override theme
- `--without-notes` (`boolean`, default: `false`): exclude speaker notes from the SPA
## `slidev export [...entry]` {#export}
Export slides to PDF (or other format). See for more details.
- `[entry]` (`string`, default: `slides.md`): path to the slides markdown entry.
Options:
- `--output` (`string`, default: use `exportFilename` (see https://sli.dev/custom/#frontmatter-configures) or use `[entry]-export`): path to the output.
- `--format` (`'pdf', 'png', 'pptx', 'md'`, default: `'pdf'`): output format.
- `--timeout` (`number`, default: `30000`): timeout for rendering the print page (see https://playwright.dev/docs/api/class-page#page-goto).
- `--range` (`string`): page ranges to export (example: `'1,4-5,6'`).
- `--dark` (`boolean`, default: `false`): export as dark theme.
- `--with-clicks`, `-c` (`boolean`, default: `false`): export pages for every click animation (see https://sli.dev/guide/animations.html#click-animation).
- `--theme`, `-t` (`string`): override theme.
- `--omit-background` (`boolean`, default: `false`): remove the default browser background
## `slidev format [entry]` {#format}
Format the markdown file. Note that this won't format the content of the slides, only the organization of the markdown file.
- `[entry]` (`string`, default: `slides.md`): path to the slides markdown entry.
## `slidev theme [subcommand]` {#theme}
Theme-related operations.
Subcommands:
- `eject [entry]`: Eject the current theme into the local file system. See .
- `[entry]` (`string`, default: `slides.md`): path to the slides markdown entry.
- Options:
- `--dir` (`string`, default: `theme`): the output dir.
- `--theme`, `-t` (`string`): override theme.
================================================
FILE: docs/builtin/components.md
================================================
# Components
This page lists all the built-in components provided by Slidev. These components can be **directly** used in your slides.
Note that can provide additional components. To add your own components, see .
## `Arrow`
Draw an arrow.
### Usage
```md
```
Or:
```md
```
Props:
- `x1` (`string | number`, required): start point x position
- `y1` (`string | number`, required): start point y position
- `x2` (`string | number`, required): end point x position
- `y2` (`string | number`, required): end point y position
- `width` (`string | number`, default: `2`): line width
- `color` (`string`, default: `'currentColor'`): line color
- `two-way` (`boolean`, default: `false`): draw a two-way arrow
## `VDragArrow`
An `Arrow` component that can be dragged.
### Usage
Props not related to position are the same as [the `Arrow` component](#arrow).
## `AutoFitText`
> Experimental
Box inside which the font size will automatically adapt to fit the content. Similar to PowerPoint or Keynote TextBox.
### Usage
```md
```
Props:
- `max` (`string | number`, default `100`): Maximum font size
- `min` (`string | number`, default `30`): Minimum font size
- `modelValue` (`string`, default `''`): text content
## `LightOrDark`
Use it to display one thing or another depending on the active light or dark theme.
### Usage
Use it with the two named Slots `#dark` and `#light`:
```md
Dark mode is on
Light mode is on
```
Provided props on `LightOrDark` component will be available using scoped slot props:
```md
```
You can provide markdown in the slots, but you will need to surround the content with blank lines:
```md


```
## `Link`
Insert a link you can use to navigate to a given slide.
### Usage
```md
Go to slide 42
```
Props:
- `to` (`string | number`): The path of the slide to navigate to (slides path starts from `1`)
- `title` (`string`): The title to display
One can use a string as `to`, provided the corresponding route exists, e.g.
```md
---
routeAlias: solutions
---
# Now some solutions!
```
## `PoweredBySlidev`
Renders "Powered by Slidev" with a link to the Slidev website.
## `RenderWhen`
Render slots depend on whether the context matches (for example whether we are in presenter view).
### Usage
```md
This will only be rendered in presenter view.
```
Context type: `'main' | 'visible' | 'print' | 'slide' | 'overview' | 'presenter' | 'previewNext'`
Props:
- `context` (`Context | Context[]`): a context or array of contexts you want to check for
- `'main'`: Render in slides and presenter view (equivalent to ['slide', 'presenter']),
- `'visible'`: Render the content if it is visible
- `'print'`: Render in print mode
- `'slide'`: Render in slides
- `'overview'`: Render in overview
- `'presenter'`: Render in presenter view
- `'previewNext'`: Render in presenter's next slide view
Slots:
- `#default`: Rendered when the context matches
- `#fallback`: Rendered when the context does not match
## `SlideCurrentNo`
Current slide number.
### Usage
```md
```
## `SlidesTotal`
Total number of slides.
### Usage
```md
```
## `TitleRenderer`
Insert the main title from a slide parsed as HTML.
Titles and title levels get automatically retrieved from the first title element of each slide.
You can override this automatic behavior for a slide by using the front matter syntax:
```yml
---
title: Amazing slide title
level: 2
---
```
### Usage
The `` component is a virtual component you can import with:
```js
import TitleRenderer from '#slidev/title-renderer'
```
Then you can use it with:
```md
```
Props:
- `no` (`string | number`): The number of the slide to display the title from (slides starts from `1`)
## `Toc`
Insert a Table Of Content.
If you want a slide to not appear in the `` component, you can use the `hideInToc` option in the frontmatter of the slide:
```yml
---
hideInToc: true
---
```
Titles are displayed using the [`` component](#titles)
### Usage
```md
```
Props:
- `columns` (`string | number`, default: `1`): The number of columns of the display
- `listClass` (`string | string[]`, default: `''`): Classes to apply to the table of contents list
- `maxDepth` (`string | number`, default: `Infinity`): The maximum depth level of title to display
- `minDepth` (`string | number`, default: `1`): The minimum depth level of title to display
- `mode` (`'all' | 'onlyCurrentTree'| 'onlySiblings'`, default: `'all'`):
- `'all'`: Display all items
- `'onlyCurrentTree'`: Display only items that are in current tree (active item, parents and children of active item)
- `'onlySiblings'`: Display only items that are in current tree and their direct siblings
## `Transform`
Apply scaling or transforming to elements.
### Usage
```md
```
Props:
- `scale` (`number | string`, default `1`): transform scale value
- `origin` (`string`, default `'top left'`): transform origin value
## `Tweet`
Embed a tweet.
### Usage
```md
```
Props:
- `id` (`number | string`, required): id of the tweet
- `scale` (`number | string`, default `1`): transform scale value
- `conversation` (`string`, default `'none'`): [tweet embed parameter](https://developer.twitter.com/en/docs/twitter-for-websites/embedded-tweets/guides/embedded-tweet-parameter-reference)
- `cards` (`'hidden' | 'visible'`, default `'visible'`): [tweet embed parameter](https://developer.twitter.com/en/docs/twitter-for-websites/embedded-tweets/guides/embedded-tweet-parameter-reference)
## `VAfter`, `VClick` and `VClicks`
## `VSwitch`
Switch between multiple slots based on clicks.
- If the `unmount` prop is set to `true`, the previous slot will be unmounted when switching to the next slot. Default is `false`.
- Use the `tag` and `childTag` props to change the default tag of the component and its children. Default is `div`.
- Use the `transition` prop to change the transition effect. Default is `false` (disabled).
## `VDrag`
## `SlidevVideo`
Embed a video.
### Usage
```md
Your browser does not support videos. You may download it
here.
```
Check [HTML video element's doc](https://developer.mozilla.org/docs/Web/HTML/Element/Video) to see what can be included in this component's slot.
Props:
- `controls` (`boolean`, default: `false`): show the video controls
- `autoplay` (`boolean | 'once'`, default: `false`):
- `true` or `'once'`: start the video only once and does not restart it once ended or paused
- `false`: never automatically start the video (rely on `controls` instead)
- `autoreset` (`'slide' | 'click'`, default: `undefined`):
- `'slide'`: go back to the start of the video when going back to the slide
- `'click'`: go back to the start of the video when going back to the component's click turn
- `poster` (`string | undefined`, default: `undefined`):
- The source of the image to print when the video is not playing.
- `printPoster` (`string | undefined`, default: `undefined`):
- The override for `poster` when printing.
- `timestamp` (`string | number`, default: `0`):
- The starting time of the video in seconds.
- `printTimestamp` (`string | number | 'last' | undefined`, default: `undefined`):
- The override for `timestamp` when printing.
::: warning
When exporting, the video may fail to load because Chromium does not support some video formats. In this case, you can specify the executable path of the browser. See [Chromium executable path](/guide/exporting.html#executable-path) for more information.
:::
## `Youtube`
Embed a YouTube video.
### Usage
```md
```
Props:
- `id` (`string`, required): id of the YouTube video
- `width` (`number`): width of the video
- `height` (`number`): height of the video
You can also make the video start at a specific time if you add `?start=1234` to the id value (where `1234` is seconds),
================================================
FILE: docs/builtin/layouts.md
================================================
# Layouts
This page lists all the built-in layouts provided by Slidev. These layouts can be used via the `layout` option in the frontmatters of your slides.
Note that may provide additional layouts or override the existing ones. To add your own layouts, see .
## `center`
Displays the content in the middle of the screen.
## `cover`
Used to display the cover page for the presentation, may contain the presentation title, contextualization, etc.
## `default`
The most basic layout, to display any kind of content.
## `end`
The final page for the presentation.
## `fact`
To show some fact or data with a lot of prominence on the screen.
## `full`
Use all the space of the screen to display the content.
## `image-left`
Shows an image on the left side of the screen, the content will be placed on the right side.
### Usage
```yaml
---
layout: image-left
# the image source
image: /path/to/the/image
# a custom class name to the content
class: my-cool-content-on-the-right
---
```
## `image-right`
Shows an image on the right side of the screen, the content will be placed on the left side.
### Usage
```yaml
---
layout: image-right
# the image source
image: /path/to/the/image
# a custom class name to the content
class: my-cool-content-on-the-left
---
```
## `image`
Shows an image as the main content of the page.
### Usage
```yaml
---
layout: image
# the image source
image: /path/to/the/image
---
```
You can change the default background size (`cover`) by adding the `backgroundSize` attribute:
```yaml
---
layout: image
image: /path/to/the/image
backgroundSize: contain
---
```
```yaml
---
layout: image-left
image: /path/to/the/image
backgroundSize: 20em 70%
---
```
## `iframe-left`
Shows a web page on the left side of the screen, the content will be placed on the right side.
### Usage
```yaml
---
layout: iframe-left
# the web page source
url: https://github.com/slidevjs/slidev
# a custom class name to the content
class: my-cool-content-on-the-right
---
```
## `iframe-right`
Shows a web page on the right side of the screen, the content will be placed on the left side.
### Usage
```yaml
---
layout: iframe-right
# the web page source
url: https://github.com/slidevjs/slidev
# a custom class name to the content
class: my-cool-content-on-the-left
---
```
## `iframe`
Shows a web page as the main content of the page.
### Usage
```yaml
---
layout: iframe
# the web page source
url: https://github.com/slidevjs/slidev
---
```
## `intro`
To introduce the presentation, usually with the presentation title, a short description, the author, etc.
## `none`
A layout without any existing styling.
## `quote`
To display a quotation with prominence.
## `section`
Used to mark the beginning of a new presentation section.
## `statement`
Make an affirmation/statement as the main page content.
## `two-cols`
Separates the page content in two columns.
### Usage
```md
---
layout: two-cols
---
# Left
This shows on the left
::right::
# Right
This shows on the right
```
## `two-cols-header`
Separates the upper and lower lines of the page content, and the second line separates the left and right columns.
### Usage
```md
---
layout: two-cols-header
---
This spans both
::left::
# Left
This shows on the left
::right::
# Right
This shows on the right
```
================================================
FILE: docs/custom/config-code-runners.md
================================================
# Configure Code Runners
Define code runners for custom languages in your Monaco Editor.
By default, JavaScript, TypeScript runners are supported built-in. They run in the browser **without** a sandbox environment. If you want more advanced integrations, you can provide your own code runner that sends the code to a remote server, runs in a Web Worker, or anything, up to you.
Create `./setup/code-runners.ts` with the following content:
```ts twoslash [setup/code-runners.ts]
/* eslint-disable import/first */
declare const executePythonCodeRemotely: (code: string) => Promise
declare const sanitizeHtml: (html: string) => string
// ---cut---
import { defineCodeRunnersSetup } from '@slidev/types'
export default defineCodeRunnersSetup(() => {
return {
async python(code, ctx) {
// Somehow execute the code and return the result
const result = await executePythonCodeRemotely(code)
return {
text: result
}
},
html(code, ctx) {
return {
html: sanitizeHtml(code)
}
},
// or other languages, key is the language id
}
})
```
## Runner Context
The second argument `ctx` is the runner context, which contains the following properties:
```ts twoslash
import type { CodeRunnerOutputs } from '@slidev/types'
import type { CodeToHastOptions } from 'shiki'
// ---cut---
export interface CodeRunnerContext {
/**
* Options passed to runner via the `runnerOptions` prop.
*/
options: Record
/**
* Highlight code with shiki.
*/
highlight: (code: string, lang: string, options?: Partial) => string
/**
* Use (other) code runner to run code.
*/
run: (code: string, lang: string) => Promise
}
```
## Runner Output
The runner can either return a text or HTML output, or an element to be mounted. Refer to https://github.com/slidevjs/slidev/blob/main/packages/types/src/code-runner.ts for more details.
## Additional Runner Dependencies
By default, Slidev will scan the Markdown source and automatically import the necessary dependencies for the code runners. If you want to manually import dependencies, you can use the `monacoRunAdditionalDeps` option in the [headmatter](./index#headmatter):
```yaml
monacoRunAdditionalDeps:
- ./path/to/dependency
- lodash-es
```
::: tip
The paths are resolved relative to the `snippets` directory. And the names of the deps should be exactly the same as the imported ones in the code.
:::
================================================
FILE: docs/custom/config-context-menu.md
================================================
# Configure Context Menu
Customize the context menu items in Slidev.
Create `./setup/context-menu.ts` with the following content:
```ts twoslash [./setup/context-menu.ts]
// ---cut---
import { useNav } from '@slidev/client'
import { defineContextMenuSetup } from '@slidev/types'
import { computed } from 'vue'
// ---cut-start---
// @ts-expect-error missing types
// ---cut-end---
import Icon3DCursor from '~icons/carbon/3d-cursor'
export default defineContextMenuSetup((items) => {
const { isPresenter } = useNav()
return computed(() => [
...items.value,
{
small: false,
icon: Icon3DCursor, // if `small` is `true`, only the icon is shown
label: 'Custom Menu Item', // or a Vue component
action() {
alert('Custom Menu Item Clicked!')
},
disabled: isPresenter.value,
},
])
})
```
This will append a new menu item to the context menu.
To disable context menu globally, set `contextMenu` to `false` in the frontmatter. `contextMenu` can also be set to `dev` or `build` to only enable the context menu in development or build mode.
================================================
FILE: docs/custom/config-fonts.md
================================================
# Configure Fonts
While you can use HTML and CSS to customize the fonts and style for your slides as you want, Slidev also provides a convenient way to use them effortlessly.
In your frontmatter, configure as the following:
```yaml
---
fonts:
# basically the text
sans: Robot
# use with `font-serif` css class from UnoCSS
serif: Robot Slab
# for code blocks, inline code, etc.
mono: Fira Code
---
```
And that's all.
Fonts will be **imported automatically from a provider via CDN, by default it is [Google Fonts](https://fonts.google.com/)**. That means you can use any fonts available on Google Fonts directly.
## Local Fonts
By default, Slidev assumes all the fonts specified via `fonts` configurations come from Google Fonts. If you want to use local fonts, specify the `fonts.local` to opt-out the auto-importing.
```yaml
---
fonts:
# like font-family in css, you can use `,` to separate multiple fonts for fallback
sans: 'Helvetica Neue,Robot'
# mark 'Helvetica Neue' as local font
local: Helvetica Neue
---
```
## Weights & Italic
By default, Slidev imports three weights `200`,`400`,`600` for each font. You can configure them by:
```yaml
---
fonts:
sans: Robot
# default
weights: '200,400,600'
# import italic fonts, default `false`
italic: false
---
```
This configuration applies to all web fonts. For more fine-grained controls of each font's weights, you will need to manually import them with [HTML](/custom/directory-structure.html#index-html) and CSS.
## Fallback Fonts
For most of the scenarios, you only need to specify the "special font" and Slidev will append the fallback fonts for you, for example:
```yaml
---
fonts:
sans: Robot
serif: Robot Slab
mono: Fira Code
---
```
will result in
```css
.font-sans {
font-family: "Robot",ui-sans-serif,system-ui,-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Arial,"Noto Sans",sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol","Noto Color Emoji";
}
.font-serif {
font-family: "Robot Slab",ui-serif,Georgia,Cambria,"Times New Roman",Times,serif;
}
.font-mono {
font-family: "Fira Code",ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,"Liberation Mono","Courier New",monospace;
}
```
If you want to disable the fallback fonts, configure as the following:
```yaml
---
fonts:
mono: 'Fira Code, monospace'
fallbacks: false
---
```
## Providers
- Options: `google` | `coollabs` | `none`
- Default: `google`
Currently, only [Google Fonts](https://fonts.google.com/) and [coolLabs](https://fonts.coollabs.io/) supported, we are planning to add more providers in the future. Specify to `none` will disable the auto-importing feature entirely and treat all the fonts locally.
```yaml
---
fonts:
provider: none
---
```
================================================
FILE: docs/custom/config-highlighter.md
================================================
# Configure Highlighter
Slidev uses [Shiki](https://github.com/shikijs/shiki) as the code highlighter. It's a TextMate Grammar powered syntax highlighter as accurate as VS Code. It generates colored tokens so no additinal CSS is required. Shiki also comes with [a bunch of built-in themes](https://shiki.style/themes). In Slidev, we also provided the [TwoSlash](#twoslash-integration) support.
## Configure Shiki
Create `./setup/shiki.ts` file with the following content:
```ts twoslash [setup/shiki.ts]
import { defineShikiSetup } from '@slidev/types'
export default defineShikiSetup(() => {
return {
themes: {
dark: 'min-dark',
light: 'min-light',
},
transformers: [
// ...
],
}
})
```
If you want to add custom theme or language (TextMate grammar/themes in JSON), you can import them in the setup file:
```ts twoslash [setup/shiki.ts]
import { defineShikiSetup } from '@slidev/types'
// ---cut-start---
// @ts-expect-error missing types
// ---cut-end---
import customLanguage from './customLanguage.tmLanguage.json'
// ---cut-start---
// @ts-expect-error missing types
// ---cut-end---
import customTheme from './customTheme.tmTheme.json'
export default defineShikiSetup(() => {
return {
themes: {
dark: customTheme,
light: 'min-light',
},
langs: [
'js',
'typescript',
'cpp',
customLanguage,
// ...
],
transformers: [
// ...
],
}
})
```
Check [Built-in languages](https://shiki.style/languages) and [Built-in themes](https://shiki.style/themes), and refer to [Shiki's docs](https://shiki.style) for more details.
:::info
For now, Shiki Magic Move does not support transformers.
:::
## Configure Prism
:::warning
Prism support has been removed since v0.50. Please use Shiki instead.
:::
================================================
FILE: docs/custom/config-katex.md
================================================
# Configure KaTeX
Create `./setup/katex.ts` with the following content:
```ts twoslash [setup/katex.ts]
import { defineKatexSetup } from '@slidev/types'
export default defineKatexSetup(() => {
return {
maxExpand: 2000,
/* ... */
}
})
```
The return value should be the custom options for KaTeX. Refer to [KaTeX's documentation](https://katex.org/docs/options.html) or the type definition for the full options list.
================================================
FILE: docs/custom/config-mermaid-renderer.md
================================================
# Configure Mermaid Renderer
1. The user installs the Mermaid library they want to use. e.g.) `npm install beautiful-mermaid`
2. Create `./setup/mermaid-renderer.ts` with the following content:
```ts
// setup/mermaid-renderer.ts
import { defineMermaidRendererSetup } from '@slidev/types'
// example. https://github.com/lukilabs/beautiful-mermaid?tab=readme-ov-file#readme
import { renderMermaid } from 'beautiful-mermaid'
export default defineMermaidRendererSetup(() => {
return (code, _options) => renderMermaid(code)
})
```
This setting allows you to use the 3rd party Mermaid library. Replace the `renderMermaid()` part with the render function of the library.
================================================
FILE: docs/custom/config-mermaid.md
================================================
# Configure Mermaid
Create `./setup/mermaid.ts` with the following content:
```ts twoslash [setup/mermaid.ts]
import { defineMermaidSetup } from '@slidev/types'
export default defineMermaidSetup(() => {
return {
theme: 'forest',
}
})
```
The return value should be the custom configs for [Mermaid](https://mermaid.js.org/). Refer to the [Mermaid documentation](https://mermaid.js.org/config/schema-docs/config.html) or the type definition for the full config list.
## Custom theme/styles
In case you want to create your custom Mermaid themes or styles, you can do this by defining `themeVariables` like in the following example:
```ts twoslash
import { defineMermaidSetup } from '@slidev/types'
export default defineMermaidSetup(() => {
return {
theme: 'base',
themeVariables: {
// General theme variables
noteBkgColor: '#181d29',
noteTextColor: '#F3EFF5cc',
noteBorderColor: '#404551',
// Sequence diagram variables
actorBkg: '#0E131F',
actorBorder: '#44FFD2',
actorTextColor: '#F3EFF5',
actorLineColor: '#F3EFF5',
signalColor: '#F3EFF5',
signalTextColor: '#F3EFF5',
}
}
})
```
You can find all theme variables on the [Mermaid Theme Configuration](https://mermaid.js.org/config/theming.html) page.
================================================
FILE: docs/custom/config-monaco.md
================================================
# Configure Monaco
Create `./setup/monaco.ts` with the following content:
```ts twoslash [./setup/monaco.ts]
import { defineMonacoSetup } from '@slidev/types'
export default defineMonacoSetup(async (monaco) => {
// use `monaco` to configure
})
```
Learn more about [configuring Monaco](https://github.com/Microsoft/monaco-editor).
## TypeScript Types
When using TypeScript with Monaco, types for dependencies will be installed to the client-side automatically.
````md
```ts {monaco}
import { ref } from 'vue'
import { useMouse } from '@vueuse/core'
const counter = ref(0)
```
````
In the example above, make sure `vue` and `@vueuse/core` are installed locally as dependencies / devDependencies, Slidev will handle the rest to get the types working for the editor automatically. When deployed as SPA, those types will also be bundled for static hosting.
### Additional Types
Slidev will scan all the Monaco code blocks in your slides and import the types for those used libraries for you. In case it missed some, you can explicitly specify extra packages to import the types for:
```md
---
monacoTypesAdditionalPackages:
- lodash-es
- foo
---
```
### Auto Type Acquisition
You can optionally switch to load types from CDN by setting the following headmatter:
```md
---
monacoTypesSource: ata
---
```
This feature is powered by [`@typescript/ata`](https://github.com/microsoft/TypeScript-Website/tree/v2/packages/ata) and runs completely on the client-side.
## Configure Themes
Since v0.48.0, Monaco will reuse the Shiki theme you configured in [Shiki's setup file](/custom/config-highlighter#configure-shiki), powered by [`@shikijs/monaco`](https://shiki.style/packages/monaco). You don't need to worry about it anymore and it will have a consistent style with the rest of your code blocks.
## Configure the Editor
> Available since v0.43.0
If you would like to customize the Monaco editor you may pass an `editorOptions` object that matches the [Monaco IEditorOptions](https://microsoft.github.io/monaco-editor/docs.html#interfaces/editor.IEditorOptions.html) definition.
````md
```ts {monaco} { editorOptions: { wordWrap:'on'} }
console.log('HelloWorld')
```
````
Alternatively if you would like these options to be applied to every Monaco instance, you can return them in the `defineMonacoSetup` function
```ts twoslash [./setup/monaco.ts]
import { defineMonacoSetup } from '@slidev/types'
export default defineMonacoSetup(() => {
return {
editorOptions: {
wordWrap: 'on'
}
}
})
```
## Disabling
Since v0.48.0, the Monaco editor is enabled by default and only be bundled when you use it. If you want to disable it, you can set `monaco` to `false` in the frontmatter of your slide:
```yaml
---
monaco: false # can also be `dev` or `build` to conditionally enable it
---
```
## Strict Mode {#strict-mode}
> Available since v0.52.0
By default, Monaco runnable code executes in strict mode (`"use strict"`). You can disable this if your code relies on non-strict mode behavior:
```yaml
---
monacoRunUseStrict: false
---
```
## Configure Code Runners
To configure how the Monaco Runner runs the code, or to add support for custom languages, please reference [Configure Code Runners](/custom/config-code-runners).
================================================
FILE: docs/custom/config-parser.md
================================================
# Configure Pre-Parser
::: info
Custom pre-parsers are not supposed to be used too often. Usually you can use [Transformers](./config-transformers) for custom syntaxes.
:::
Slidev parses your presentation file (e.g. `slides.md`) in three steps:
1. A "preparsing" step is carried out: the file is split into slides using the `---` separator, and considering the possible frontmatter blocks.
2. Each slide is parsed with an external library.
3. Slidev resolves the special frontmatter property `src: ....`, which allows to include other md files.
## Markdown Parser
Configuring the markdown parser used in step 2 can be done by [configuring Vite internal plugins](/custom/config-vite#configure-internal-plugins).
## Preparser Extensions
> Available since v0.37.0.
::: warning
Important: when modifying the preparser configuration, you need to stop and start Slidev again (restart might not be sufficient).
:::
The preparser (step 1 above) is highly extensible and allows you to implement custom syntaxes for your md files. Extending the preparser is considered **an advanced feature** and is susceptible to breaking [editor integrations](../features/side-editor) due to implicit changes in the syntax.
To customize it, create a `./setup/preparser.ts` file with the following content:
```ts twoslash [./setup/preparser.ts]
import { definePreparserSetup } from '@slidev/types'
export default definePreparserSetup(({ filepath, headmatter, mode }) => {
return [
{
transformRawLines(lines) {
for (const i in lines) {
if (lines[i] === '@@@')
lines[i] = 'HELLO'
}
},
}
]
})
```
This example systematically replaces any `@@@` line with a line with `hello`. It illustrates the structure of a preparser configuration file and some of the main concepts the preparser involves:
- `definePreparserSetup` must be called with a function as parameter.
- The function receives the file path (of the root presentation file), the headmatter (from the md file) and, since v0.48.0, a mode (dev, build or export). It could use this information (e.g., enable extensions based on the presentation file or whether we are exporting a PDF).
- The function must return a list of preparser extensions.
- An extension can contain:
- a `transformRawLines(lines)` function that runs just after parsing the headmatter of the md file and receives a list of all lines (from the md file). The function can mutate the list arbitrarily.
- a `transformSlide(content, frontmatter)` function that is called for each slide, just after splitting the file, and receives the slide content as a string and the frontmatter of the slide as an object. The function can mutate the frontmatter and must return the content string (possibly modified, possibly `undefined` if no modifications have been done).
- a `transformNote(note, frontmatter)` function that is called for each slide, just after splitting the file, and receives the slide note as a string or undefined and the frontmatter of the slide as an object. The function can mutate the frontmatter and must return the note string (possibly modified, possibly `undefined` if no modifications have been done).
- a `name`
## Example Preparser Extensions
### Use case 1: compact syntax top-level presentation
Imagine a situation where (part of) your presentation is mainly showing cover images and including other md files. You might want a compact notation where for instance (part of) `slides.md` is as follows:
```md
@cover: /nice.jpg
# Welcome
@src: page1.md
@src: page2.md
@cover: /break.jpg
@src: pages3-4.md
@cover: https://cover.sli.dev
# Questions?
see you next time
```
To allow these `@src:` and `@cover:` syntaxes, create a `./setup/preparser.ts` file with the following content:
```ts twoslash [./setup/preparser.ts]
import { definePreparserSetup } from '@slidev/types'
export default definePreparserSetup(() => {
return [
{
transformRawLines(lines) {
let i = 0
while (i < lines.length) {
const l = lines[i]
if (l.match(/^@cover:/i)) {
lines.splice(
i,
1,
'---',
'layout: cover',
`background: ${l.replace(/^@cover: */i, '')}`,
'---',
''
)
continue
}
if (l.match(/^@src:/i)) {
lines.splice(
i,
1,
'---',
`src: ${l.replace(/^@src: */i, '')}`,
'---',
''
)
continue
}
i++
}
}
},
]
})
```
And that's it.
### Use case 2: using custom frontmatter to wrap slides
Imagine a case where you often want to scale some of your slides but still want to use a variety of existing layouts so creating a new layout would not be suited.
For instance, you might want to write your `slides.md` as follows:
```md
---
layout: quote
_scale: 0.75
---
# Welcome
> great!
---
_scale: 4
---
# Break
---
# Ok
---
layout: center
_scale: 2.5
---
# Questions?
see you next time
```
Here we used an underscore in `_scale` to avoid possible conflicts with existing frontmatter properties (indeed, the case of `scale`, without underscore would cause potential problems).
To handle this `_scale: ...` syntax in the frontmatter, create a `./setup/preparser.ts` file with the following content:
```ts twoslash [./setup/preparser.ts]
import { definePreparserSetup } from '@slidev/types'
export default definePreparserSetup(() => {
return [
{
async transformSlide(content, frontmatter) {
if ('_scale' in frontmatter) {
return [
``,
'',
content,
'',
''
].join('\n')
}
},
},
]
})
```
And that's it.
### Use case 3: using custom frontmatter to transform note
Imagine a case where you want to replace the slides default notes with custom notes.
For instance, you might want to write your `slides.md` as follows:
```md
---
layout: quote
_note: notes/note.md
---
# Welcome
> great!
```
Here we used an underscore in `_note` to avoid possible conflicts with existing frontmatter properties.
To handle this `_note: ...` syntax in the frontmatter, create a `./setup/preparser.ts` file with the following content:
```ts twoslash [./setup/preparser.ts]
import fs, { promises as fsp } from 'node:fs'
import { definePreparserSetup } from '@slidev/types'
export default definePreparserSetup(() => {
return [
{
async transformNote(note, frontmatter) {
if ('_note' in frontmatter && fs.existsSync(frontmatter._note)) {
try {
const newNote = await fsp.readFile(frontmatter._note, 'utf8')
return newNote
}
catch (err) {
}
}
return note
},
},
]
})
```
================================================
FILE: docs/custom/config-routes.md
================================================
# Configure Routes
Add custom pages to the Slidev app.
## Usage
Create `./setup/routes.ts` with the following content:
```ts twoslash [./setup/routes.ts]
import { defineRoutesSetup } from '@slidev/types'
export default defineRoutesSetup((routes) => {
return [
...routes,
{
path: '/my-page',
// ---cut-start---
// @ts-expect-error missing types
// ---cut-end---
component: () => import('../pages/my-page.vue'),
},
]
})
```
Learn more about routes in the [Vue Router documentation](https://router.vuejs.org/).
================================================
FILE: docs/custom/config-shortcuts.md
================================================
# Configure Shortcuts
## Getting started
Create `./setup/shortcuts.ts` with the following content:
```ts twoslash [./setup/shortcuts.ts]
import type { NavOperations, ShortcutOptions } from '@slidev/types'
import { defineShortcutsSetup } from '@slidev/types'
export default defineShortcutsSetup((nav: NavOperations, base: ShortcutOptions[]) => {
return [
...base, // keep the existing shortcuts
{
key: 'enter',
fn: () => nav.next(),
autoRepeat: true,
},
{
key: 'backspace',
fn: () => nav.prev(),
autoRepeat: true,
},
]
})
```
In the setup function, you can customize the keyboard shortcuts by returning a new array of shortcuts. The above example binds the `next` operation to enter and the `prev` operation to backspace.
Please refer to [Navigation Actions](../guide/ui#navigation-actions) section for the default shortcuts and navigation operations.
## Key Binding Format
The `key` of each shortcut can be either a string (e.g. `'Shift+Ctrl+A'`) or a computed boolean. Please refer to [`useMagicKeys` from VueUse](https://vueuse.org/core/useMagicKeys/) for
================================================
FILE: docs/custom/config-transformers.md
================================================
# Configure Transformers
This setup function allows you to define custom transformers for the markdown content of **each slide**. This is useful when you want to add custom Markdown syntax and render custom code blocks. To start, create a `./setup/transformers.ts` file with the following content:
````ts twoslash [setup/transformers.ts]
import type { MarkdownTransformContext } from '@slidev/types'
import { defineTransformersSetup } from '@slidev/types'
function myCodeblock(ctx: MarkdownTransformContext) {
console.log('index in presentation', ctx.slide.index)
ctx.s.replace(
/^```myblock *(\{[^\n]*\})?\n([\s\S]+?)\n```/gm,
(full, options = '', code = '') => {
return `...`
},
)
}
export default defineTransformersSetup(() => {
return {
pre: [],
preCodeblock: [myCodeblock],
postCodeblock: [],
post: [],
}
})
````
The return value should be the custom options for the transformers. The `pre`, `preCodeblock`, `postCodeblock`, and `post` are arrays of functions that will be called in order to transform the markdown content. The order of the transformers is:
1. `pre` from your project
2. `pre` from addons and themes
3. Import snippets syntax and Shiki magic move
4. `preCodeblock` from your project
5. `preCodeblock` from addons and themes
6. Built-in special code blocks like Mermaid, Monaco and PlantUML
7. `postCodeblock` from addons and themes
8. `postCodeblock` from your project
9. Other built-in transformers like code block wrapping
10. `post` from addons and themes
11. `post` from your project
================================================
FILE: docs/custom/config-unocss.md
================================================
# Configure UnoCSS
[UnoCSS](https://unocss.dev) is now the default CSS framework for Slidev since v0.42.0. UnoCSS is a fast atomic CSS engine that has full flexibility and extensibility. Most of the Tailwind CSS classes are supported **out-of-box**, and you can also extend it with your own configurations.
By default, Slidev enables the following presets out-of-box:
- [@unocss/preset-wind3](https://unocss.dev/presets/wind3) - Tailwind / Windi CSS compatible utilities
- [@unocss/preset-attributify](https://unocss.dev/presets/attributify) - Attributify mode
- [@unocss/preset-icons](https://unocss.dev/presets/icons) - Use any icons as class
- [@unocss/preset-web-fonts](https://unocss.dev/presets/web-fonts) - Use web fonts at ease
- [@unocss/transformer-directives](https://unocss.dev/transformers/directives) - Use `@apply` in CSS
Slidev also adds shortcuts as can be seen in its [source code](https://github.com/slidevjs/slidev/blob/main/packages/client/uno.config.ts).
You can therefore style your content the way you want. For example:
```html
### Name
- Item 1
- Item 2
```
## Configurations
You can create `uno.config.ts` under the root of your project to extend the builtin configurations
```ts twoslash [uno.config.ts]
import { defineConfig } from 'unocss'
export default defineConfig({
shortcuts: {
// custom the default background
'bg-main': 'bg-white text-[#181818] dark:(bg-[#121212] text-[#ddd])',
},
// ...
})
```
Learn more about [UnoCSS configurations](https://unocss.dev/guide/config-file)
================================================
FILE: docs/custom/config-vite.md
================================================
# Configure Vite and Plugins
Slidev is powered by [Vite](https://vitejs.dev/) under the hood. This means you can leverage Vite's great plugin system to customize your slides even further.
The `vite.config.ts` will be respected if you have one, and will be merged with the Vite config provided by Slidev, your theme and the addons.
## Configure Internal Plugins
Slidev internally adds the following plugins to Vite:
- [@vitejs/plugin-vue](https://github.com/vitejs/vite-plugin-vue)
- [unplugin-vue-components](https://github.com/unplugin/unplugin-vue-components)
- [unplugin-icons](https://github.com/unplugin/unplugin-icons)
- [vite-plugin-vue-markdown](https://github.com/unplugin/unplugin-vue-markdown)
- [vite-plugin-remote-assets](https://github.com/antfu/vite-plugin-remote-assets)
- [unocss/vite](https://github.com/unocss/unocss/tree/main/packages/vite)
To configure the built-in plugins listed above, create a `vite.config.ts` with the following content. Please note that Slidev has some [default configurations](https://github.com/slidevjs/slidev/blob/main/packages/slidev/node/vite/index.ts) for those plugins, this usage will override some of them, which may potentially cause the app to break. Please treat this as **an advanced feature**, and make sure you know what you are doing before moving on.
```ts twoslash [vite.config.ts]
/* eslint-disable import/first */
///
import type MarkdownExit from 'markdown-exit'
declare const MyPlugin: (md: any) => void
// ---cut---
import { defineConfig } from 'vite'
export default defineConfig({
slidev: {
vue: {
/* vue options */
},
markdown: {
/* markdown-exit options */
markdownSetup(md) {
/* custom markdown-exit plugins */
md.use(MyPlugin)
},
},
/* options for other plugins */
},
})
```
See the [type declarations](https://github.com/slidevjs/slidev/blob/main/packages/types/src/vite.ts#L11) for more options.
::: warning
It is not allowed to re-add plugins that has been used internally be Slidev. For example, instead of
```ts twoslash
import Vue from '@vitejs/plugin-vue'
import { defineConfig } from 'vite'
export default defineConfig({
plugins: [
Vue({
/* vue options */
})
],
})
```
Please pass the Vue options to the `slidev.vue` field as described above
:::
## Add Custom Plugins based on Slide data
Usually you can add Vite plugins into your `vite.config.ts` (see above).
However, if you want to add plugins based on the slide data, you need to add a `./setup/vite-plugins.ts` with the following content:
```ts twoslash
import { defineVitePluginsSetup } from '@slidev/types'
export default defineVitePluginsSetup((options) => {
return [
// Your plugins here
// Slide data is available as options.data.slides
]
})
```
================================================
FILE: docs/custom/config-vue.md
================================================
# Configure Vue App
Slidev uses [Vue 3](https://v3.vuejs.org/) to render the application on the client side. You can extend the app to add custom plugins or configurations.
Create `./setup/main.ts` with the following content:
```ts twoslash [setup/main.ts]
/* eslint-disable import/first */
import type { Plugin } from 'vue'
declare const YourPlugin: Plugin
// ---cut---
import { defineAppSetup } from '@slidev/types'
export default defineAppSetup(({ app, router }) => {
// Vue App
app.use(YourPlugin)
})
```
This can also be used as the main entrance of your Slidev app to do some initializations before the app starts.
Learn more: [Vue Application API](https://v3.vuejs.org/api/application-api.html#component).
================================================
FILE: docs/custom/directory-structure.md
================================================
# Directory Structure
Slidev employs some directory structure conventions to minimize the configuration surface and to make the functionality extensions flexible and intuitive.
The conventional directory structure is:
```bash
your-slidev/
├── components/ # custom components
├── layouts/ # custom layouts
├── public/ # static assets
├── setup/ # custom setup / hooks
├── snippets/ # code snippets
├── styles/ # custom style
├── index.html # injections to index.html
├── slides.md # the main slides entry
└── vite.config.ts # extending vite config
```
All of them are optional.
## Components
Pattern: `./components/*.{vue,js,ts,jsx,tsx,md}`
## Layouts
Pattern: `./layouts/*.{vue,js,ts,jsx,tsx}`
## Public
Pattern: `./public/*`
Assets in this directory will be served at root path `/` during dev, and copied to the root of the dist directory as-is. Read more about [Assets Handling](../guide/faq#assets-handling).
## Style
Pattern: `./style.css` | `./styles/index.{css,js,ts}`
Files following this convention will be injected to the App root. If you need to import multiple CSS entries, you can create the following structure and manage the import order yourself.
:::warning
Global CSS here also applies to the presenter UI. Prefer scoping styles to individual slides, or wrap your selectors under `.slidev-layout` to avoid leaking styles into presenter mode.
**Example:** Use `.slidev-layout .grid { ... }` instead of just `.grid { ... }`.
:::
```bash
your-slidev/
├── ...
└── styles/
├── index.ts
├── base.css
├── code.css
└── layouts.css
```
```ts
// styles/index.ts
import './base.css'
import './code.css'
import './layouts.css'
```
Styles will be processed by [UnoCSS](https://unocss.dev/) and [PostCSS](https://postcss.org/), so you can use CSS nesting and [at-directives](https://unocss.dev/transformers/directives#apply) and Nested CSS out-of-box. For example:
```css
.slidev-layout {
--uno: px-14 py-10 text-[1.1rem];
h1, h2, h3, h4, p, div {
--uno: select-none;
}
pre, code {
--uno: select-text;
}
a {
color: theme('colors.primary');
}
}
```
Learn more about the syntax [here](https://unocss.dev/transformers/directives#apply).
## `index.html`
Pattern: `index.html`
The `index.html` provides the ability to inject meta tags and/or scripts to the main `index.html`
For example, for the following custom `index.html`:
```html [index.html]
```
The final hosted `index.html` will be:
```html
```
## Global Layers
Pattern: `global-top.vue` | `global-bottom.vue` | `custom-nav-controls.vue` | `slide-top.vue` | `slide-bottom.vue`
================================================
FILE: docs/custom/index.md
================================================
# Customizations
Slidev is fully customizable, from styling to tooling configurations. It allows you to configure the tools underneath ([Vite](/custom/config-vite), [UnoCSS](/custom/config-unocss), [Monaco](/custom/config-monaco), etc.)
## Slides Deck Configs {#headmatter}
You can configure the whole slides project in the frontmatter of your **first** slide (i.e. headmatter). The following shows the default value for each option:
```yaml
---
# theme id, package name, or local path
# Learn more: https://sli.dev/guide/theme-addon.html#use-theme
theme: default
# addons, can be a list of package names or local paths
# Learn more: https://sli.dev/guide/theme-addon.html#use-addon
addons: []
# title of your slide, will inferred from the first header if not specified
title: Slidev
# titleTemplate for the webpage, `%s` will be replaced by the slides deck's title
titleTemplate: '%s - Slidev'
# information for your slides, can be a Markdown string
info: false
# author field for exported PDF or PPTX
author: Your Name Here
# keywords field for exported PDF, comma-delimited
keywords: keyword1,keyword2
# enable presenter mode, can be boolean, 'dev' or 'build'
presenter: true
# enable browser exporter, can be boolean, 'dev' or 'build'
browserExporter: dev
# enabled pdf downloading in SPA build, can also be a custom url
download: false
# filename of the export file
exportFilename: slidev-exported
# export options
# use export CLI options in camelCase format
# Learn more: https://sli.dev/guide/exporting.html
export:
format: pdf
timeout: 30000
dark: false
withClicks: false
withToc: false
# enable twoslash, can be boolean, 'dev' or 'build'
twoslash: true
# show line numbers in code blocks
lineNumbers: false
# enable monaco editor, can be boolean, 'dev' or 'build'
monaco: true
# Where to load monaco types from, can be 'cdn', 'local' or 'none'
monacoTypesSource: local
# explicitly specify extra local packages to import the types for
monacoTypesAdditionalPackages: []
# explicitly specify extra local modules as dependencies of monaco runnable
monacoRunAdditionalDeps: []
# download remote assets in local using vite-plugin-remote-assets, can be boolean, 'dev' or 'build'
remoteAssets: false
# controls whether texts in slides are selectable
selectable: true
# enable slide recording, can be boolean, 'dev' or 'build'
record: dev
# enable Slidev's context menu, can be boolean, 'dev' or 'build'
contextMenu: true
# enable wake lock, can be boolean, 'dev' or 'build'
wakeLock: true
# take snapshot for each slide in the overview
overviewSnapshots: false
# force color schema for the slides, can be 'auto', 'light', or 'dark'
colorSchema: auto
# router mode for vue-router, can be "history" or "hash"
routerMode: history
# aspect ratio for the slides
aspectRatio: 16/9
# real width of the canvas, unit in px
canvasWidth: 980
# used for theme customization, will inject root styles as `--slidev-theme-x` for attribute `x`
themeConfig:
primary: '#5d8392'
# favicon, can be a local file path or URL
favicon: 'https://cdn.jsdelivr.net/gh/slidevjs/slidev/assets/favicon.png'
# URL of PlantUML server used to render diagrams
# Learn more: https://sli.dev/features/plantuml.html
plantUmlServer: https://www.plantuml.com/plantuml
# fonts will be auto-imported from Google fonts
# Learn more: https://sli.dev/custom/config-fonts.html
fonts:
sans: Roboto
serif: Roboto Slab
mono: Fira Code
# default frontmatter applies to all slides
defaults:
layout: default
# ...
# drawing options
# Learn more: https://sli.dev/guide/drawing.html
drawings:
enabled: true
persist: false
presenterOnly: false
syncAll: true
# HTML tag attributes
htmlAttrs:
dir: ltr
lang: en
# SEO meta tags
seoMeta:
ogTitle: Slidev Starter Template
ogDescription: Presentation slides for developers
ogImage: https://cover.sli.dev
ogUrl: https://example.com
twitterCard: summary_large_image
twitterTitle: Slidev Starter Template
twitterDescription: Presentation slides for developers
twitterImage: https://cover.sli.dev
twitterSite: username
twitterUrl: https://example.com
---
```
Check out the [type definitions](https://github.com/slidevjs/slidev/blob/main/packages/types/src/config.ts) for more details.
## Per-slide Configs {#frontmatter}
Also every slide accepts the following configuration in its frontmatter block. The following shows the default value for each option:
```yaml
---
# custom clicks count
# Learn more: https://sli.dev/guide/animations#total
clicks: 0
# custom start clicks count
clicksStart: 0
# completely disable and hide the slide
disabled: false
# the same as `disabled`
hide: false
# hide the slide for the components
hideInToc: false
# defines the layout component applied to the slide
layout: <"cover" if the slide is the first slide, otherwise "default">
# override the title level for the and components
# only if `title` has also been declared
level: 1
# mount this slide before entering
preload: true
# create a route alias that can be used in the URL or with the component
routeAlias: undefined # or string
# includes a markdown file
# Learn more: https://sli.dev/guide/syntax.html#importing-slides
src: undefined # or string
# override the title for the and components
# only if `title` has also been declared
title: undefined # or string
# defines the transition between the slide and the next one
# Learn more: https://sli.dev/guide/animations.html#slide-transitions
transition: undefined # or BuiltinSlideTransition | string | TransitionGroupProps | null
# custom zoom scale
# useful for slides with a lot of content
zoom: 1
# used as positions of draggable elements
# Learn more: https://sli.dev/features/draggable.html
dragPos: {} # type: Record
---
```
Check out the [type definition](https://github.com/slidevjs/slidev/blob/main/packages/types/src/frontmatter.ts#L260) for more details.
## Directory Structure
Slidev uses directory structure conventions to minimalize the configuration surface and make extensions in functionality flexible and intuitive.
Refer to the [Directory Structure](/custom/directory-structure) section.
## Config Tools
{{ c.text }}
================================================
FILE: docs/features/block-frontmatter.md
================================================
---
depends:
- guide/syntax
relates:
- features/prettier-plugin
tags: [syntax]
description: |
Use a YAML code block as the frontmatter.
---
# Block Frontmatter
The usual way to define frontmatters of slides is concise, but may lack of highlighting and formatter support. To solve this, you can use a YAML block at the very beginning of the slide content as the frontmatter of the slide:
````md
---
theme: default
---
# Slide 1
---
```yaml
layout: quote
```
# Slide 2
---
# Slide 3
````
::: warning About headmatter
Headmatter in Slidev is exactly the usual called "frontmatter" of the a Markdown file, which is supported by most of the Markdown editors and formatters. So you can't use a YAML block as the headmatter of the whole slide deck.
:::
================================================
FILE: docs/features/build-with-pdf.md
================================================
---
depends:
- guide/exporting
- guide/hosting
relates:
- CLI export options: /builtin/cli#export
- Headmatter export options: /custom/#headmatter
tags: [export, build]
description: |
Generate a downloadable PDF along with your slides build.
---
# Generate PDF when Building
You can provide a downloadable PDF in your built slides with the following config in headmatter:
```md
---
download: true
---
```
Slidev will generate a PDF file along with the build, and a download button will be displayed in the build.
You can also provide a custom URL for the PDF. In that case, the rendering process will be skipped.
```md
---
download: 'https://myside.com/my-talk.pdf'
---
```
This can also be done with the CLI option `--download` (`boolean` only).
```bash
$ slidev build --download
```
When using the download option, you can also provide the export options via:
- [CLI export options](/builtin/cli#export)
- [Headmatter export options](/custom/#frontmatter-configures)
================================================
FILE: docs/features/bundle-remote-assets.md
================================================
---
relates:
- vite-plugin-remote-assets: https://github.com/antfu/vite-plugin-remote-assets
tags: [build]
description: |
Download and bundle remote assets when building your slides.
---
# Bundle Remote Assets
Just like you would do in markdown, you can use images pointing to a remote or local URL.
For remote assets, the built-in [`vite-plugin-remote-assets`](https://github.com/antfu/vite-plugin-remote-assets) will cache them onto the disk at first run, ensuring instant loading even for large images later on.
```md

```
For local assets, put them into the [`public` folder](/custom/directory-structure.html#public) and reference them with a **leading slash** (i.e., `/pic.png`, NOT `./pic.png`, which is relative to the working file).
```md

```
If you want to apply custom sizes or styles, you can convert them to the `` tag:
```html
```
================================================
FILE: docs/features/canvas-size.md
================================================
---
relates:
- guide/faq#adjust-size
- features/zoom-slide
- features/transform-component
tags: [layout]
description: |
Set the size for all your slides.
---
# Slide Canvas Size
Slidev allows you to set the size of the slide canvas via the `canvasWidth` and `aspectRatio` options in the headmatter:
```md
---
# aspect ratio for the slides
aspectRatio: 16/9
# real width of the canvas, unit in px
canvasWidth: 980
---
# Your slides here
```
To scale several slides in your presentation, you can use the `zoom` option:
To adjust the size of some elements on your slides, you can use the `Transform` component:
================================================
FILE: docs/features/click-marker.md
================================================
---
depends:
- guide/syntax#notes
- guide/animations
since: v0.48.0
tags: [presenter, animation]
description: |
Highlighting notes and auto-scrolling to the active section of notes.
---
# Click Markers
For some slides you may have longer notes that could be hard to find your place. Slidev supports click markers that allow highlighting and auto-scrolling to the section of notes from your corresponding content. Put `[click]` markers at the beginning of any line in your notes for the timing you need to go to another [click](/guide/animations#click-animation). You may skip `n` clicks by using `[click:{n+1}]`. For example:
```md
```
Slidev divides the content between the click markers and highlights it in presenter notes, synchronized with your slide progress.
================================================
FILE: docs/features/code-block-line-numbers.md
================================================
---
depends:
- guide/syntax#code-block
tags: [codeblock]
description: |
Enable line numbering for all code blocks across the slides or individually.
---
# Line Numbers
You can enable line numbering for all code blocks across the slides by setting `lineNumbers: true` in the headmatter, or enable each code block individually by setting `lines: true`.
You can also set the starting line for each code block and highlight the lines accordingly via `{startLine: number}`, which defaults to 1.
````md
```ts {6,7}{lines:true,startLine:5}
function add(
a: Ref | number,
b: Ref | number
) {
return computed(() => unref(a) + unref(b))
}
```
````
Note that you can use `{*}` as a placeholder of :
````md
```ts {*}{lines:true,startLine:5}
// ...
```
````
================================================
FILE: docs/features/code-block-max-height.md
================================================
---
depends:
- guide/syntax#code-block
tags: [codeblock, layout]
description: |
Set a maximum height for a code block and enable scrolling.
---
# Max Height
If the code doesn't fit into one slide, you use the `maxHeight` to set a fixed height and enable scrolling:
````md
```ts {2|3|7|12}{maxHeight:'100px'}
function add(
a: Ref | number,
b: Ref | number
) {
return computed(() => unref(a) + unref(b))
}
/// ...as many lines as you want
const c = add(1, 2)
```
````
Note that you can use `{*}` as a placeholder of :
````md
```ts {*}{maxHeight:'100px'}
// ...
```
````
================================================
FILE: docs/features/code-groups.md
================================================
---
depends:
- guide/syntax#code-block
tags: [codeblock]
description: |
Group multiple code blocks and automatically match icon by the title name.
---
# Code Groups
> [!NOTE]
> This feature requires [Comark Syntax](/features/comark#comark-syntax). Enable `comark: true` to use it.
You can group multiple code blocks like this:
````md
::code-group
```sh [npm]
npm i @slidev/cli
```
```sh [yarn]
yarn add @slidev/cli
```
```sh [pnpm]
pnpm add @slidev/cli
```
::
````
## Title Icon Matching
`code groups`, `code block` and [`Shiki Magic Move`](/features/shiki-magic-move) also supports the automatically icon matching by the title name.

::: info
By default, we provide some built-in icons, you can use them by install [@iconify-json/vscode-icons](https://www.npmjs.com/package/@iconify-json/vscode-icons).
:::
::: details All built-in icons
```js
const builtinIcons = {
// package managers
'pnpm': 'i-vscode-icons:file-type-light-pnpm',
'npm': 'i-vscode-icons:file-type-npm',
'yarn': 'i-vscode-icons:file-type-yarn',
'bun': 'i-vscode-icons:file-type-bun',
'deno': 'i-vscode-icons:file-type-deno',
// frameworks
'vue': 'i-vscode-icons:file-type-vue',
'svelte': 'i-vscode-icons:file-type-svelte',
'angular': 'i-vscode-icons:file-type-angular',
'react': 'i-vscode-icons:file-type-reactjs',
'next': 'i-vscode-icons:file-type-light-next',
'nuxt': 'i-vscode-icons:file-type-nuxt',
'solid': 'logos:solidjs-icon',
'astro': 'i-vscode-icons:file-type-light-astro',
// bundlers
'rollup': 'i-vscode-icons:file-type-rollup',
'webpack': 'i-vscode-icons:file-type-webpack',
'vite': 'i-vscode-icons:file-type-vite',
'esbuild': 'i-vscode-icons:file-type-esbuild',
// configuration files
'package.json': 'i-vscode-icons:file-type-node',
'tsconfig.json': 'i-vscode-icons:file-type-tsconfig',
'.npmrc': 'i-vscode-icons:file-type-npm',
'.editorconfig': 'i-vscode-icons:file-type-editorconfig',
'.eslintrc': 'i-vscode-icons:file-type-eslint',
'.eslintignore': 'i-vscode-icons:file-type-eslint',
'eslint.config': 'i-vscode-icons:file-type-eslint',
'.gitignore': 'i-vscode-icons:file-type-git',
'.gitattributes': 'i-vscode-icons:file-type-git',
'.env': 'i-vscode-icons:file-type-dotenv',
'.env.example': 'i-vscode-icons:file-type-dotenv',
'.vscode': 'i-vscode-icons:file-type-vscode',
'tailwind.config': 'vscode-icons:file-type-tailwind',
'uno.config': 'i-vscode-icons:file-type-unocss',
'unocss.config': 'i-vscode-icons:file-type-unocss',
'.oxlintrc': 'i-vscode-icons:file-type-oxlint',
'vue.config': 'i-vscode-icons:file-type-vueconfig',
// filename extensions
'.mts': 'i-vscode-icons:file-type-typescript',
'.cts': 'i-vscode-icons:file-type-typescript',
'.ts': 'i-vscode-icons:file-type-typescript',
'.tsx': 'i-vscode-icons:file-type-typescript',
'.mjs': 'i-vscode-icons:file-type-js',
'.cjs': 'i-vscode-icons:file-type-js',
'.json': 'i-vscode-icons:file-type-json',
'.js': 'i-vscode-icons:file-type-js',
'.jsx': 'i-vscode-icons:file-type-js',
'.md': 'i-vscode-icons:file-type-markdown',
'.py': 'i-vscode-icons:file-type-python',
'.ico': 'i-vscode-icons:file-type-favicon',
'.html': 'i-vscode-icons:file-type-html',
'.css': 'i-vscode-icons:file-type-css',
'.scss': 'i-vscode-icons:file-type-scss',
'.yml': 'i-vscode-icons:file-type-light-yaml',
'.yaml': 'i-vscode-icons:file-type-light-yaml',
'.php': 'i-vscode-icons:file-type-php',
}
```
:::
## Custom Icons
You can use any name from the [iconify](https://icones.js.org) collection by using the `~icon~` syntax, for example:
````md
```js [npm ~i-uil:github~]
console.log('Hello, GitHub!')
```
````
To make it work, you need to:
1. Install the icon's collection.
:::code-group
```sh [npm]
npm add @iconify-json/uil
```
```sh [yarn]
yarn add @iconify-json/uil
```
```sh [pnpm]
pnpm add @iconify-json/uil
```
```sh [bun]
bun add @iconify-json/uil
```
:::
2. Add the icon to the `uno.config.ts` file.
```ts [uno.config.ts] {4-6}
import { defineConfig } from 'unocss'
export default defineConfig({
safelist: [
'i-uil:github',
],
})
```
================================================
FILE: docs/features/comark.md
================================================
---
relates:
- Comark Syntax: https://comark.dev/syntax/markdown
- '@comark/markdown-it': https://github.com/comarkdown/comark
since: v0.43.0
tags: [syntax, styling]
description: |
A powerful syntax to enhance your markdown content with components and styles.
---
# Comark Syntax
Slidev supports optional [Comark Syntax](https://comark.dev/syntax/markdown) (formerly known as MDC, Markdown Components) powered by [`@comark/markdown-it`](https://github.com/comarkdown/comark).
You can enable it by adding `comark: true` to the frontmatter of your markdown file.
```mdc
---
comark: true
---
This is a [red text]{style="color:red"} :inline-component{prop="value"}
{width=500px lazy}
::block-component{prop="value"}
The **default** slot
::
```
Learn more about [Comark Syntax](https://comark.dev/syntax/markdown).
================================================
FILE: docs/features/direction-variant.md
================================================
---
relates:
- UnoCSS Variants: https://unocss.dev/config/variants#variants
since: v0.48.0
tags: [navigation, styling]
description: |
Apply different styles and animations based on the navigation direction.
---
# Navigation Direction Variants
You may want to apply different classes based on whether it's navigating forward or backward. The `.slidev-nav-go-forward` or `.slidev-nav-go-backward` class will be applied to the slide container when navigating, and you can use them to apply different styles or animations:
```css
/* example: delay on only forward but not backward */
.slidev-nav-go-forward .slidev-vclick-target {
transition-delay: 500ms;
}
.slidev-nav-go-backward .slidev-vclick-target {
transition-delay: 0;
}
```
To make it easier, we also provided some [UnoCSS variants](https://github.com/slidevjs/slidev/blob/6adcf2016b8fb0cab65cf150221f1f67a76a2dd8/packages/client/uno.config.ts#L32-L38) for this. You can use the `forward:` or `backward:` prefix to any UnoCSS classes to only enable them in the specific navigation direction:
```html
Element
// [!code --]
Element
// [!code ++]
```
In the above example, the animation is only delayed when navigating forward.
================================================
FILE: docs/features/draggable.md
================================================
---
tags: [layout]
description: |
Move, resize, and rotate elements by dragging them with the mouse.
---
# Draggable Elements
Draggable elements give you the ability to move, resize, and rotate elements by dragging them with the mouse. This is useful for creating floating elements in your slides.
## Directive Usage
### Data from the frontmatter
```md
---
dragPos:
square: Left,Top,Width,Height,Rotate
---
```
### Data from the directive value
::: warning
Slidev use regex to update the position value in the slide content. If you meet problems, please use the frontmatter to define the values instead.
:::
```md
```
## Component Usage
### Data from the frontmatter
```md
---
dragPos:
foo: Left,Top,Width,Height,Rotate
---
Use the `v-drag` component to have a draggable container!
```
### Data from props
```md
Use the `v-drag` component to have a draggable container!
```
## Create a Draggable Element
When you create a new draggable element, you don't need to specify the position value (but you need to specify the position name if you want to use the frontmatter). Slidev will automatically generate the initial position value for you.
## Automatic Height
You can set `Height` to `NaN` (in) or `_` (if you use the component) to make the height of the draggable element automatically adjust to its content.
## Controls
- Double-click the draggable element to start dragging it.
- You can also use the arrow keys to move the element.
- Hold `Shift` while dragging to preserve its aspect ratio.
- Click outside the draggable element to stop dragging it.
## Draggable Arrow
The `` component creates a draggable arrow element. Simply use it like this:
```md
```
And you will get a draggable arrow element. Other props are the same as [the `Arrow` component](/builtin/components#arrow).
================================================
FILE: docs/features/drawing.md
================================================
---
depends:
- guide/ui#navigation-bar
relates:
- drauu: https://github.com/antfu/drauu
tags: [drawing]
description: |
Draw and annotate your slides with ease.
---
# Drawing & Annotations
Slidev comes with a built-in drawing and annotation feature powered by [drauu](https://github.com/antfu/drauu). It allows you to draw and annotate your slides with ease.
To start, click the icon in the [navigation bar](../guide/ui#navigation-bar) to open the drawing toolbar. It's also available in the [Presenter Mode](/guide/ui#presenter-mode). Drawings and annotations you created will be **synced** automatically across all instances in real-time.
## Use with Stylus Pen
When using a stylus pen on a tablet (for example, iPad with Apple Pencil), Slidev will intelligently detect the input type. You can directly draw on your slides with the pen without turning on the drawing mode while having your fingers or mouse control the navigation.
## Persist Drawings
The following frontmatter configuration allows you to persist your drawings as SVGs under `.slidev/drawings` directory and have them inside your exported PDF or hosted site.
```md
---
drawings:
persist: true
---
```
## Disable Drawings
Entirely:
```md
---
drawings:
enabled: false
---
```
Only in Development:
```md
---
drawings:
enabled: dev
---
```
Only in Presenter Mode:
```md
---
drawings:
presenterOnly: true
---
```
## Drawing Syncing
By default, Slidev syncs up your drawings across all instances. If you are sharing your slides with others, you might want to disable the syncing via:
```md
---
drawings:
syncAll: false
---
```
With this config, only the drawing from the presenter instance will be able to sync with others.
================================================
FILE: docs/features/eject-theme.md
================================================
---
depends:
- guide/theme-addon
tags: [theme, cli]
description: |
Eject the installed theme from your project to customize it.
---
# Eject Theme
If you want to get full control of the current theme, you can **eject** it to your local file system and modify it as you want. By running the following command
```bash
$ slidev theme eject
```
It will eject the theme you are using currently into `./theme`, and change your frontmatter to
```yaml
---
theme: ./theme
---
```
This could also be helpful if you want to make a theme based on an existing one. If you do, remember to mention the original theme and the author :)
For more options of the `theme` command, please refer to the [Theme Command](../builtin/cli#theme) section.
================================================
FILE: docs/features/frontmatter-merging.md
================================================
---
depends:
- guide/syntax#importing-slides
- features/importing-slides
tags: [syntax]
description: |
Merge frontmatter from multiple markdown files.
---
# Frontmatter Merging
You can provide frontmatter instructions from both your main entry and external markdown pages. If there are duplicate keys in them, the ones from the **main entry have the higher priority**. For example:
::: code-group
```md [./slides.md]
---
src: ./cover.md
background: https://sli.dev/bar.png // [!code highlight]
class: text-center
---
```
```md [./cover.md]
---
layout: cover
background: https://sli.dev/foo.png // [!code highlight]
---
# Cover
Cover Page
```
:::
They will end up being equivalent to the following page:
```md
---
layout: cover
background: https://sli.dev/bar.png // [!code highlight]
class: text-center
---
# Cover
Cover Page
```
================================================
FILE: docs/features/global-layers.md
================================================
---
tags: [navigation, layout]
description: |
Create custom components that persist across slides.
---
# Global Layers
Global layers allow you to have custom components that **persist** across slides. This could be useful for having footers, cross-slide animations, global effects, etc.
Slidev provides three layers for this usage, create `global-top.vue`, `global-bottom.vue`, or `custom-nav-controls.vue` under your project root and it will pick up automatically.
There are also layers for **each** slide: `slide-top.vue` and `slide-bottom.vue`. The usage is similar to the global layers, but they are applied to every slide, so there may be more than one instance of them.
::: tip
If you are using `global-top.vue` or `global-bottom.vue` depending on the current navigation state, when exporting, the `--per-slide` option should be used to ensure the correct state is applied to each slide. Or you can use `slide-top.vue` and `slide-bottom.vue` instead.
:::
## Layers relationship
At z-axis, from top to bottom:
- NavControls
- Customized Navigation Controls (`custom-nav-controls.vue`)
- Global Top (`global-top.vue`) - single instance
- Slide Top (`slide-top.vue`) - instance per slide
- Slide Content
- Slide Bottom (`slide-bottom.vue`) - instance per slide
- Global Bottom (`global-bottom.vue`) - single instance
## Example
```html
```
The text `Your Name` will appear on all your slides.
```html
```
The button `Next` will appear in NavControls.
To enable it conditionally, you can use the
```html
```
```html
```
```html
```
```html
```
================================================
FILE: docs/features/icons.md
================================================
---
relates:
- Iconify: https://iconify.design/
- Icones: https://icones.js.org/
- unplugin-icons: https://github.com/antfu/unplugin-icons
tags: [components]
description: |
Use icons from virtually all open-source icon sets directly in your markdown.
---
# Icons
Slidev allows you to have access to virtually all open-source icon sets **directly** in your markdown after installing the corresponding package. Powered by [`unplugin-icons`](https://github.com/antfu/unplugin-icons) and [Iconify](https://iconify.design/).
The naming follows [Iconify](https://iconify.design/)'s convention of `{collection-name}-{icon-name}`. For example:
- `` - from [Material Design Icons](https://github.com/Templarian/MaterialDesign) - [`@iconify-json/mdi`](https://npmjs.com/package/@iconify-json/mdi)
- `` - from [Carbon](https://github.com/carbon-design-system/carbon/tree/main/packages/icons) - [`@iconify-json/carbon`](https://npmjs.com/package/@iconify-json/carbon)
- `` - from [Unicons Monochrome](https://github.com/Iconscout/unicons) - [`@iconify-json/uim`](https://npmjs.com/package/@iconify-json/uim)
- `` - from [Twemoji](https://github.com/twitter/twemoji) - [`@iconify-json/twemoji`](https://npmjs.com/package/@iconify-json/twemoji)
- `` - from [SVG Logos](https://github.com/gilbarbara/logos) - [`@iconify-json/logos`](https://npmjs.com/package/@iconify-json/logos)
- And much more...
::: code-group
```bash [pnpm]
pnpm add @iconify-json/[the-collection-you-want]
```
```bash [npm]
npm install @iconify-json/[the-collection-you-want]
```
```bash [yarn]
yarn add @iconify-json/[the-collection-you-want]
```
```bash [bun]
bun add @iconify-json/[the-collection-you-want]
```
```bash [deno]
deno add jsr:@iconify-json/[the-collection-you-want]
```
:::
We use [Iconify](https://iconify.design) as our data source of icons. You need to install the corresponding icon-set in `dependencies` by following the `@iconify-json/*` pattern. For example, `@iconify-json/mdi` for [Material Design Icons](https://materialdesignicons.com/), `@iconify-json/tabler` for [Tabler](https://tabler-icons.io/). You can refer to [Icônes](https://icones.js.org/) or [Iconify](https://icon-sets.iconify.design/) for all the collections available.
### Styling Icons
You can style the icons just like other HTML elements. For example:
```html
```
================================================
FILE: docs/features/import-snippet.md
================================================
---
relates:
- features/monaco-write
- features/monaco-editor
since: v0.47.0
tags: [codeblock, syntax]
description: |
Import code snippets from existing files into your slides.
---
# Import Code Snippets
You can import code snippets from existing files via the following syntax:
```md
<<< @/snippets/snippet.js
```
::: tip
The value of `@` corresponds to your package's root directory. It's recommended to put snippets in `@/snippets` in order to be compatible with the Monaco editor. Alternatively, you can also import from relative paths.
:::
You can also use a [VS Code region](https://code.visualstudio.com/docs/editor/codebasics#_folding) to only include the corresponding part of the code file:
```md
<<< @/snippets/snippet.js#region-name
```
To explicitly specify the language of the imported code, you can add a language identifier after:
```md
<<< @/snippets/snippet.js ts
```
Any code block features like [line highlighting](#line-highlighting) and [Monaco editor](#monaco-editor) are also supported:
```md
<<< @/snippets/snippet.js {2,3|5}{lines:true}
<<< @/snippets/snippet.js ts {monaco}{height:200px}
```
Note that you can use `{*}` as a placeholder of :
```md
<<< @/snippets/snippet.js {*}{lines:true}
```
================================================
FILE: docs/features/importing-slides.md
================================================
---
relates:
- features/frontmatter-merging
tags: [syntax]
description: |
Split your `slides.md` into multiple files for better reusability and organization.
---
# Importing Slides
You can split your `slides.md` into multiple files for better reusability and organization. To do this, you can use the `src` frontmatter option to specify the path to the external markdown file. For example:
::: code-group
```md [./slides.md]
# Title
This is a normal page
---
src: ./pages/toc.md // [!code highlight]
---
Contents here are ignored
---
# Page 4
Another normal page
---
src: ./pages/toc.md # Reuse the same file // [!code highlight]
---
```
```md [./pages/toc.md]
# Table of Contents
Part 1
---
# Table of Contents
Part 2
```
:::
## Importing Specific Slides
To reuse some of the slides inside another Markdown file, you can use the hash part of the import path:
```md
---
src: ./another-presentation.md#2,5-7
---
```
This will import the slides 2, 5, 6, and 7 from `./another-presentation.md`.
## Frontmatter Merging
================================================
FILE: docs/features/index.data.ts
================================================
import { basename } from 'node:path'
import { createContentLoader } from 'vitepress'
export interface Feature {
name: string
title: string
link: string
description: string
depends: string[]
relates: string[]
derives: string[]
tags: string[]
since?: string
}
export default createContentLoader('features/*.md', {
includeSrc: true,
transform(data) {
const derivesMap: Record = {}
for (const md of data) {
const name = basename(md.url, '.md')
if (name === 'index' || name === 'features')
continue
for (const depend of md.frontmatter.depends ?? []) {
const dependName = depend.match(/\/([\w-]+)($|#)/)?.[1]
if (dependName) {
derivesMap[dependName] ??= []
derivesMap[dependName].push(`features/${name}`)
}
}
}
const result: Record = {}
for (const md of data) {
const name = basename(md.url, '.md')
if (name === 'index' || name === 'features')
continue
const title = md.src?.match(/^# (.*)$/m)?.[1]?.trim() ?? name
const derives = md.frontmatter.derives ?? []
for (const d of derivesMap[name] ?? []) {
if (!derives.includes(d)) {
derives.push(d)
}
}
result[name] = {
name,
title,
link: `/features/${name}.html`,
description: md.frontmatter.description ?? '',
depends: md.frontmatter.depends ?? [],
relates: md.frontmatter.relates ?? [],
derives,
tags: md.frontmatter.tags ?? [],
since: md.frontmatter.since,
}
}
return result
},
})
export declare const data: Record
================================================
FILE: docs/features/index.md
================================================
---
editLink: false
footer: false
aside: false
outline: false
sidebar: false
pageClass: all-features-page
---
# Features
This is a list of all the individual features that Slidev provides. Each feature can be used independently and is optional.
You can also read to learn the features by topic.
No results found
================================================
FILE: docs/features/latex.md
================================================
---
relates:
- Demo: /demo/starter/11
- KaTeX: https://katex.org/
tags: [codeblock, syntax]
description: |
Slidev comes with LaTeX support out-of-box, powered by KaTeX.
---
# LaTeX
Slidev comes with LaTeX support out-of-box, powered by [KaTeX](https://katex.org/).
## Inline
Surround your LaTeX with a single `$` on each side for inline rendering.
```md
$\sqrt{3x-1}+(1+x)^2$
```
## Block
Use two (`$$`) for block rendering. This mode uses bigger symbols and centers
the result.
```latex
$$
\begin{aligned}
\nabla \cdot \vec{E} &= \frac{\rho}{\varepsilon_0} \\
\nabla \cdot \vec{B} &= 0 \\
\nabla \times \vec{E} &= -\frac{\partial\vec{B}}{\partial t} \\
\nabla \times \vec{B} &= \mu_0\vec{J} + \mu_0\varepsilon_0\frac{\partial\vec{E}}{\partial t}
\end{aligned}
$$
```
## Line Highlighting
To highlight specific lines, simply add line numbers within bracket `{}`. Line numbers start counting from 1 by default.
```latex
$$ {1|3|all}
\begin{aligned}
\nabla \cdot \vec{E} &= \frac{\rho}{\varepsilon_0} \\
\nabla \cdot \vec{B} &= 0 \\
\nabla \times \vec{E} &= -\frac{\partial\vec{B}}{\partial t} \\
\nabla \times \vec{B} &= \mu_0\vec{J} + \mu_0\varepsilon_0\frac{\partial\vec{E}}{\partial t}
\end{aligned}
$$
```
The `at` and `finally` options of [code blocks](#line-highlighting) are also available for LaTeX blocks.
## Chemical equations
To enable the rendering of chemical equations, the [mhchem](https://github.com/KaTeX/KaTeX/tree/main/contrib/mhchem)
KaTeX extension needs to be loaded.
Create `vite.config.ts` with the following content:
```ts
import 'katex/contrib/mhchem'
export default {}
```
Now chemical equations can be rendered properly.
```latex
$$
\displaystyle{\ce{B(OH)3 + H2O <--> B(OH)4^- + H+}}
$$
```
Learn more: [Syntax](https://mhchem.github.io/MathJax-mhchem)
---
================================================
FILE: docs/features/line-highlighting.md
================================================
---
depends:
- guide/syntax#code-block
- guide/animations
tags: [codeblock, animation]
description: |
Highlight specific lines in code blocks based on clicks.
---
# Line Highlighting
To highlight specific lines, simply add line numbers within brackets `{}`. Line numbers start counting from 1 by default.
````md
```ts {2,3}
function add(
a: Ref | number,
b: Ref | number
) {
return computed(() => unref(a) + unref(b))
}
```
````
## Dynamic Line Highlighting
To change what's highlighted with multiple clicks, you can use `|` to separate each stage:
````md
```ts {2-3|5|all}
function add(
a: Ref | number,
b: Ref | number
) {
return computed(() => unref(a) + unref(b))
}
```
````
This will first highlight `a: Ref | number` and `b: Ref | number`, and then `return computed(() => unref(a) + unref(b))` after one click, and lastly, the whole block.
You can set the line number to `hide` to hide the code block or `none` to not highlight any line:
````md
```ts {hide|none}
function add(
a: Ref | number,
b: Ref | number
) {
return computed(() => unref(a) + unref(b))
}
```
````
::: tip
Learn more in the [click animations guide](/guide/animations#positioning).
:::
================================================
FILE: docs/features/mermaid.md
================================================
---
relates:
- Mermaid: https://mermaid.js.org/
- Mermaid Live Editor: https://mermaid.live/
- Demo Slide: https://sli.dev/demo/starter/12
- features/plantuml
tags: [diagram]
description: |
Create diagrams/graphs from textual descriptions, powered by Mermaid.
---
# Mermaid Diagrams
You can also create diagrams/graphs from textual descriptions in your Markdown, powered by [Mermaid](https://mermaid.js.org/).
Code blocks marked as `mermaid` will be converted to diagrams, for example:
````md
```mermaid
sequenceDiagram
Alice->John: Hello John, how are you?
Note over Alice,John: A typical interaction
```
````
You can further pass an options object to it to specify the scaling and theming. The syntax of the object is a JavaScript object literal, you will need to add quotes (`'`) for strings and use comma (`,`) between keys.
````md
```mermaid {theme: 'neutral', scale: 0.8}
graph TD
B[Text] --> C{Decision}
C -->|One| D[Result 1]
C -->|Two| E[Result 2]
```
````
Visit the [Mermaid Website](https://mermaid.js.org/) for more information.
================================================
FILE: docs/features/monaco-editor.md
================================================
---
depends:
- guide/syntax#code-block
relates:
- Monaco Editor: https://microsoft.github.io/monaco-editor/
- Configure Monaco Editor: /custom/config-monaco
tags: [codeblock, editor]
description: |
Turn code blocks into fully-featured editors, or generate a diff between two code blocks.
---
# Monaco Editor
Whenever you want to do some modification in the presentation, simply add `{monaco}` after the language id — it turns the block into a fully-featured Monaco editor!
````md
```ts {monaco}
console.log('HelloWorld')
```
````
Learn more about [Configuring Monaco](/custom/config-monaco).
## Diff Editor
Monaco can also generate a diff between two code blocks. Use `{monaco-diff}` to turn the block into a [Monaco diff editor](https://microsoft.github.io/monaco-editor/playground.html?source=v0.36.1#example-creating-the-diffeditor-multi-line-example) and use `~~~` to separate the original and modified code!
````md
```ts {monaco-diff}
console.log('Original text')
~~~
console.log('Modified text')
```
````
## Editor Height
By default, the Monaco editor has a fixed height based on the initial content. If you start with an empty or small code block and want the editor to automatically grow as you type more code, you can set `{height:'auto'}`.
````md
```ts {monaco} {height:'auto'}
// The editor will automatically grow as you type more code
console.log('Hello, World!')
```
````
You can also set a specific height using CSS units like `{height:'300px'}` or `{height:'100%'}`.
================================================
FILE: docs/features/monaco-run.md
================================================
---
depends:
- features/monaco-editor
- guide/animations
relates:
- Custom Code Runners: /custom/config-code-runners
since: v0.48.0
tags: [codeblock, editor]
description: |
Run code directly in the editor and see the result.
---
# Monaco Runner
Slidev also provides the Monaco Runner Editor, which allows you to run the code directly in the editor and see the result. Use `{monaco-run}` to turn the block into a Monaco Runner Editor.
````md
```ts {monaco-run}
function distance(x: number, y: number) {
return Math.sqrt(x ** 2 + y ** 2)
}
console.log(distance(3, 4))
```
````
It provides the editor with a "Run" button, and shows the result of the code execution right below the code block. You may also modify the code and the result will be re-evaluated on the fly.
By default it will automatically run the code when the slide is loaded; if you want to instead explicitly trigger the run, you can set `{autorun:false}`.
````md
```ts {monaco-run} {autorun:false}
console.log('Click the play button to run me')
```
````
If you want to only show the output in certain clicks, you can use the `showOutputAt` prop. The value is the same as `v-click`.
````md
```ts {monaco-run} {showOutputAt:'+1'}
console.log('Shown after 1 click')
```
````
Currently, Slidev supports running JavaScript and TypeScript code out-of-box. Refer to [Custom Code Runners](/custom/config-code-runners) for custom language support.
================================================
FILE: docs/features/monaco-write.md
================================================
---
depends:
- features/monaco-editor
- features/import-snippet
relates:
- features/import-snippet
- Custom Code Runners: /custom/config-code-runners
since: v0.49.5
tags: [codeblock, editor]
description: |
A monaco editor that allows you to write code directly in the slides and save the changes back to the file.
---
# Writable Monaco Editor
You can also use the [Import Code Snippets](#import-code-snippets) syntax combined with the `{monaco-write}` directive, to link your Monaco Editor with a file on your filesystem. This will allow you to edit the code directly in the editor and save the changes back to the file.
```md
<<< ./some-file.ts {monaco-write}
```
When using this, be sure to back up your files beforehand, as the changes will be saved directly to the file.
================================================
FILE: docs/features/notes-auto-ruby.md
================================================
---
tags: [notes, presenter]
description: Automatically add `` tags to your notes.
---
# Notes Auto Ruby
> Available since v52.4.0
When you write notes in your slides, you might want to add some ruby text to help pronouncing the some words. You can always add `` tags to your notes manually, but Slidev also provides a convenient way to do this automatically by a global auto-replacement.
In the headmatter, you can set the `notesAutoRuby` option to a map of words to their ruby text:
```md
---
notesAutoRuby:
日本語: ni hon go
勉強: べんきょう
---
# Your slides here
```
And the notes will be rendered as:
私は日本語を勉強しています。
================================================
FILE: docs/features/og-image.md
================================================
---
relates:
- features/seo-meta
tags: ['SEO', head]
description: |
Set the Open Graph image for your slides.
---
# Open Graph Image
Slidev allows you to set the Open Graph image via the `seoMeta.ogImage` option in the headmatter:
```md
---
seoMeta:
ogImage: https://url.to.your.image.png
---
# Your slides here
```
Learn more about [SEO Meta Tags](./seo-meta).
## Local Image
If you have `./og-image.png` in your project root, Slidev will grab it as the Open Graph image automatically without any configuration.
## Auto-generate
Since v52.1.0, Slidev supports auto-generating the Open Graph image from the first slide.
You can set `seoMeta.ogImage` to `auto` to enable this feature.
```md
---
seoMeta:
ogImage: auto
---
```
It will use [playwright](https://playwright.dev/) to capture the first slide and save it as `./og-image.png` (same as `slidev export`). You may also commit the generated image to your repository to avoid the auto-generation. Or if you generate it on CI, you might also want to setup the playwright environment.
================================================
FILE: docs/features/plantuml.md
================================================
---
relates:
- Plant UML: https://plantuml.com/
- Plant UML Live Editor: https://plantuml.com/plantuml
- Example Slide: https://sli.dev/demo/starter/12
- features/mermaid
tags: [diagram]
description: |
Create diagrams from textual descriptions, powered by PlantUML.
---
# PlantUML Diagrams
You can create PlantUML diagrams easily in your slides, for example:
````md
```plantuml
@startuml
Alice -> Bob : Hello!
@enduml
```
````
The source code will be sent to https://www.plantuml.com/plantuml to render the diagram by default. You can also set up your own server by setting the `plantUmlServer` in the [Slidev configuration](../custom/index#headmatter).
Visit the [PlantUML Website](https://plantuml.com/) for more information.
================================================
FILE: docs/features/prettier-plugin.md
================================================
---
relates:
- features/block-frontmatter
- GitHub Repo: https://github.com/slidevjs/prettier-plugin
- Prettier: https://prettier.io/
tags: [editor]
description: |
Use the Prettier plugin to format your slides.
---
# Prettier Plugin
The Slidev's syntax may be incompatible with the default Markdown parser of [Prettier](https://prettier.io/). To solve this, Slidev provides a Prettier plugin to format your slides. You can use it with your favorite editor that supports Prettier.
## 1. Install
::: code-group
```bash [npm]
npm i -D prettier prettier-plugin-slidev
```
```bash [pnpm]
pnpm i -D prettier prettier-plugin-slidev
```
```bash [yarn]
yarn add -D prettier prettier-plugin-slidev
```
```bash [bun]
bun add -D prettier prettier-plugin-slidev
```
```bash [deno]
deno add -D npm:prettier npm:prettier-plugin-slidev
```
:::
## 2. Activate the plugin
Create or modify your [prettier configuration file](https://prettier.io/docs/en/configuration) to activate the plugin:
```json
{
"overrides": [
{
"files": ["slides.md", "pages/*.md"],
"options": {
"parser": "slidev",
"plugins": ["prettier-plugin-slidev"]
}
}
]
}
```
Note that only specifying `plugins` is not enough, because Slidev and common Markdown files share the same file extension `.md`.
================================================
FILE: docs/features/recording.md
================================================
---
depends:
- guide/ui#navigation-bar
relates:
- RecordRTC: https://github.com/muaz-khan/RecordRTC
- WebRTC API: https://webrtc.org/
tags: [presenter, tool]
description: |
Record your presentation with the built-in camera view and recording feature.
---
# Recording
Slidev comes with a built-in camera view and recording feature. They make it simple for you to record your presentation without having to switch between other recording tools while delivering a presentation.
## Camera View {#camera-view}
Click the button in the [navigation bar](../guide/ui#navigation-bar) to show your camera view in the presentation. You can drag it to move it, and use the handler on the right bottom corner to resize it. The size and position will persist across reloads.
## Start Recording {#start-recording}
Clicking the button in the [navigation bar](../guide/ui#navigation-bar) will bring up a dialog for you. Here you can choose to either record your camera output embedded in your slides or to separate them into two video files.
This feature is powered by [RecordRTC](https://github.com/muaz-khan/RecordRTC) and uses the [WebRTC API](https://webrtc.org/).

================================================
FILE: docs/features/remote-access.md
================================================
---
relates:
- guide/ui
- CLI: builtin/cli
- Cloudflare Quick Tunnels: https://developers.cloudflare.com/cloudflare-one/connections/connect-networks/do-more-with-tunnels/trycloudflare/
tags: [remote, tool]
description: |
Access your presentation remotely with Slidev's remote access feature.
---
# Remote Access
You can run your presentation with remote access by using the `--remote` flag:
::: code-group
```bash [pnpm]
pnpm dev --remote
# i.e. slidev --remote
```
```bash [npm]
npm run dev -- --remote
# i.e. slidev --remote
```
```bash [yarn]
yarn dev --remote
# i.e. slidev --remote
```
```bash [bun]
bun dev --remote
# i.e. slidev --remote
```
```bash [deno]
deno run dev --remote
# i.e. slidev --remote
```
:::
## Password Protection
If you want to share your slides but don't want other people to access the presenter mode, you can pass a password to the option, i.e. `--remote=your_password`. Then the password is required when accessing the presenter mode.
## Remote Tunnel
You can open a [Cloudflare Quick Tunnels](https://developers.cloudflare.com/cloudflare-one/connections/connect-networks/do-more-with-tunnels/trycloudflare/) to expose your local server to the internet. This way, you can share your slides with others without setting up a server.
::: code-group
```bash [pnpm]
pnpm dev --remote --tunnel
# i.e. slidev --remote --tunnel
```
```bash [npm]
npm run dev -- --remote --tunnel
# i.e. slidev --remote --tunnel
```
```bash [yarn]
yarn dev --remote --tunnel
# i.e. slidev --remote --tunnel
```
```bash [bun]
bun dev --remote --tunnel
# i.e. slidev --remote --tunnel
```
```bash [deno]
deno run dev --remote --tunnel
# i.e. slidev --remote --tunnel
```
:::
================================================
FILE: docs/features/rough-marker.md
================================================
---
depends:
- guide/animations
relates:
- Rough Notation: https://github.com/slidevjs/rough-notation
since: v0.48.0
tags: [drawing, animation]
description: |
Integrate Rough Notation to allow marking or highlighting elements in your slides.
---
# Rough Markers
Slidev integrates [Rough Notation](https://github.com/slidevjs/rough-notation) to allow marking or highlighting elements in your slides.
---
### `v-mark` directive
Rough Notation integration comes with the `v-mark` directive.
#### Type
Use `v-mark.underline` for the underline mark, `v-mark.circle` for the circle mark, etc. (defaults to `underline`).
#### Color
`v-mark.red` makes the notation `red`. Supported built-in color themes from UnoCSS. For custom colors, use object syntax `v-mark="{ color: '#234' }"`.
#### Clicks
`v-mark` works like `v-click` and will trigger after a click. Same as `v-click`, it allows you to pass a custom click value, like `v-mark="5"` or `v-mark="'+1'"`.
#### Options
Optionally, you can pass an object to `v-mark` to specify the options, for example:
```vue
Important text
```
#### Preview
================================================
FILE: docs/features/seo-meta.md
================================================
---
depends:
- custom/index#headmatter
relates:
- features/og-image
tags: [SEO, head]
description: |
Configure SEO meta tags for better social media sharing and search engine optimization.
---
# SEO Meta Tags
Slidev allows you to configure SEO meta tags in the headmatter to improve social media sharing and search engine optimization. You can set up Open Graph and Twitter Card meta tags to control how your slides appear when shared on social platforms.
## Configuration
Add the `seoMeta` configuration to your slides deck frontmatter:
```yaml
---
# SEO meta tags
seoMeta:
ogTitle: Slidev Starter Template
ogDescription: Presentation slides for developers
ogImage: https://cover.sli.dev
ogUrl: https://example.com
twitterCard: summary_large_image
twitterTitle: Slidev Starter Template
twitterDescription: Presentation slides for developers
twitterImage: https://cover.sli.dev
twitterSite: username
twitterUrl: https://example.com
---
```
This feature is powered by [unhead](https://unhead.unjs.io/)'s `useHead` hook, please refer to the [documentation](https://unhead.unjs.io/docs/head/api/composables/use-seo-meta) for more details.
================================================
FILE: docs/features/shiki-magic-move.md
================================================
---
depends:
- guide/syntax#code-block
- guide/animations
relates:
- Shiki Magic Move: https://github.com/shikijs/shiki-magic-move
since: v0.48.0
tags: [codeblock, animation]
description: |
Enable granular transition between code changes, similar to Keynote's Magic Move.
---
# Shiki Magic Move
[Shiki Magic Move](https://github.com/shikijs/shiki-magic-move) enables you to have a granular transition between code changes, similar to Keynote's Magic Move. You can check [the playground](https://shiki-magic-move.netlify.app/) to see how it works.
In Slidev, we bind the magic-move to the [clicks system](/guide/animations#click-animation). The syntax is to wrap multiple code blocks representing each step with ````md magic-move (mind it's **4** backticks), this will be transformed into one code block, that morphs to each step as you click.
`````md
````md magic-move
```js
console.log(`Step ${1}`)
```
```js
console.log(`Step ${1 + 1}`)
```
```ts
console.log(`Step ${3}` as string)
```
````
`````
It's also possible to mix Magic Move with and , for example:
`````md
````md magic-move {at:4, lines: true} // [!code hl]
```js {*|1|2-5} // [!code hl]
let count = 1
function add() {
count++
}
```
Non-code blocks in between as ignored, you can put some comments.
```js {*}{lines: false} // [!code hl]
let count = 1
const add = () => count += 1
```
````
`````
## Title Bar {#title-bar}
> Available since v0.52.0
You can add a title bar to magic move blocks by specifying a filename in the opening fence of each step:
`````md
````md magic-move
```js [app.js]
console.log('Step 1')
```
```js [app.js]
console.log('Step 2')
```
````
`````
The title bar will also display an automatically matched icon based on the filename (see ).
## Animation Duration {#duration}
> Available since v0.52.0
You can customize the animation duration for magic move transitions globally via the headmatter:
```yaml
---
magicMoveDuration: 500 # duration in milliseconds, default is 800
---
```
Or per-block by passing the `duration` option:
`````md
````md magic-move {duration:500}
```js
console.log('Step 1')
```
```js
console.log('Step 2')
```
````
`````
## Copy Button {#copy-button}
> Available since v0.52.0
Magic move code blocks support a copy button that appears on hover. Configure this behavior globally with the `magicMoveCopy` headmatter option:
```yaml
---
# Options: true | false | 'always' | 'final'
magicMoveCopy: true # show copy button on all steps (default)
magicMoveCopy: false # disable copy button
magicMoveCopy: 'final' # only show copy button on the final step
---
```
The copy button respects the global `codeCopy` setting. If `codeCopy` is `false`, the magic move copy button will also be disabled.
================================================
FILE: docs/features/side-editor.md
================================================
---
depends:
- guide/ui#navigation-actions
relates:
- features/vscode-extension
tags: [editor]
description: |
Edit your slides source file alongside the presentation.
---
# Integrated Editor
Slidev comes with an integrated editor that will instantly reload and save the changes to your file.
Click the button on the navigation panel to open it.

================================================
FILE: docs/features/slide-hook.md
================================================
---
depends:
- guide/global-context
tags: [client-api]
description: |
Hooks to manage the slide lifecycle.
---
# Slide Hooks
Slidev provides a set of hooks to help you manage the slide lifecycle:
```ts twoslash
import { onSlideEnter, onSlideLeave, useIsSlideActive } from '@slidev/client'
const isActive = useIsSlideActive()
onSlideEnter(() => {
/* Called whenever the slide becomes active */
})
onSlideLeave(() => {
/* Called whenever the slide becomes inactive */
})
```
You can also use to access other useful context information.
::: warning
In the slide component, `onMounted` and `onUnmounted` hooks are not available, because the component instance is preserved even when the slide is not active. Use `onSlideEnter` and `onSlideLeave` instead.
:::
================================================
FILE: docs/features/slide-scope-style.md
================================================
---
relates:
- Vue's Scoped CSS: https://vuejs.org/api/sfc-css-features.html#scoped-css
- UnoCSS directives: https://unocss.dev/transformers/directives
tags: [styling, syntax]
description: |
Define styles for only the current slide.
---
# Slide Scope Styles
You can use the `
---
# Other slides are not affected
```
The `
```
================================================
FILE: docs/features/slot-sugar.md
================================================
---
relates:
- Vue's Named Slots: https://v3.vuejs.org/guide/component-slots.html
tags: [layout, syntax]
description: |
A syntax sugar for named slots in layouts.
---
# Slot Sugar for Layouts
Some layouts can provide multiple contributing points using [Vue's named slots](https://vuejs.org/guide/components/slots.html).
For example, in [`two-cols` layout](https://github.com/slidevjs/slidev/blob/main/packages/client/layouts/two-cols.vue), you can have two columns left (`default` slot) and right (`right` slot) side by side.
```md
---
layout: two-cols
---
# Left
This is shown on the left
# Right
This is shown on the right
```
Left
This shows on the left
Right
This shows on the right
We also provide a shorthand syntactical sugar `::name::` for slot name. The following works exactly the same as the previous example.
```md
---
layout: two-cols
---
# Left
This is shown on the left
::right::
# Right
This is shown on the right
```
You can also explicitly specify the default slot and provide it in the custom order.
```md
---
layout: two-cols
---
::right::
# Right
This shows on the right
::default::
# Left
This is shown on the left
```
================================================
FILE: docs/features/timer.md
================================================
---
tags: [presenter]
description: Timer for the presenter mode.
---
# Presenter Timer
Slidev provides a timer for the presenter mode. You can start, pause, and reset the timer.
It will show a timer (in stopwatch or countdown mode), and a progress bar in the presenter mode.
## Configuration
You can set the duration of the presentation in the headmatter. Default is `30min`.
```yaml
---
# duration of the presentation, default is '30min'
duration: 30min
# timer mode, can be 'countdown' or 'stopwatch', default is 'stopwatch'
timer: stopwatch
---
```
================================================
FILE: docs/features/transform-component.md
================================================
---
relates:
- guide/faq#adjust-size
- features/canvas-size
- features/zoom-slide
tags: [layout]
description: |
A component for scaling some elements.
---
# The `Transform` Component
The `Transform` component allows you to scale the size of the elements on your slides:
```md
```
This is useful when you want to adjust the size of some elements on your slides without affecting the layout of the entire slide.
To scale all the slides in your presentation, you can set the slide canvas size:
To scale several slides in your presentation, you can use the `zoom` option:
================================================
FILE: docs/features/twoslash.md
================================================
---
depends:
- guide/syntax#code-block
relates:
- TwoSlash: https://twoslash.netlify.app/
since: v0.46.0
tags: [codeblock]
description: |
A powerful tool for rendering TypeScript code blocks with type information on hover or inlined.
---
# TwoSlash Integration
[TwoSlash](https://twoslash.netlify.app/) is a powerful tool for rendering TypeScript code blocks with type information on hover or inlined. It's quite useful for preparing slides for JavaScript/TypeScript-related topics.
To use it, you can add `twoslash` to the code block's language identifier:
````md
```ts twoslash
import { ref } from 'vue'
const count = ref(0)
// ^?
```
````
It will be rendered as:
```ts twoslash
import { ref } from 'vue'
const count = ref(0)
// ^?
```
================================================
FILE: docs/features/vscode-extension.md
================================================
---
relates:
- VS Code: https://code.visualstudio.com/
- View in Marketplace: https://marketplace.visualstudio.com/items?itemName=antfu.slidev
- View in OVSX: https://open-vsx.org/extension/antfu/slidev
tags: [editor]
description: |
Help you better organize your slides and have a quick overview of them.
---
# VS Code Extension
The VS Code extension provides some features to help you better organize your slides and have a quick overview of them.
### Features
- Preview slides in the side panel
- Slides tree view with slide numbers
- Re-ordering slides via drag and drop
- Folding for slide blocks
- Multiple slides project support
- Start the dev server with one click
- AI/Copilot integration via Language Model Tools

### Installation
You can install the extension from the [VS Code Marketplace](https://marketplace.visualstudio.com/items?itemName=antfu.slidev) or the [Open VSX Registry](https://open-vsx.org/extension/antfu/slidev).
### Usage
Click the `Slidev` icon in the activity bar to open the **Slidev panel**. In the Slidev panel, you can see the projects tree view, slides tree view, and the preview webview.
In the **projects tree view**, you can see all the Slidev projects in your workspace. You can click the item to open the corresponding file, and click the icon over it to switch the active project. The icon allows you to load a slides project that wasn't scanned automatically.
In the **slides tree view**, you can see all the slides in the active project. You can click the item to move your cursor to the slide in the editor, and drag and drop to reorder the slides.
In the **preview webview**, you can click the icon to start the dev server and click the icon to open the slides in the browser. Toggle icon to sync/unsync the preview navigation with the editor cursor.
There are also some **commands** you can use. Type `Slidev` in the command palette to see them.
You can add glob patterns to the `slidev.include` configuration to include files as Slidev entries. The default value is `["**/*.md"]`. Example:
```json
{
"slidev.include": ["**/presentation.md"]
}
```
#### Dev Command {#dev-command}
You can customize the command to start dev server by setting the `slidev.dev-command` configuration. The default value is `npm exec -c 'slidev ${args}'`.
The configured command can contain placeholders:
- `${args}`: All CLI arguments. e.g. `slides.md --port 3000 --remote`
- `${port}`: The port number. e.g. `3000`
Examples:
- Global installation: `slidev ${args}`
- For PNPM users, you can set it to `pnpm slidev ${args}`.
- For [code-server](https://coder.com/docs/code-server/) users, you can set it to `pnpm slidev ${args} --base /proxy/${port}/`. This will make the dev server accessible at `http://localhost:8080/proxy/3000/`.
#### Slides Tree View {#slides-tree}
> Available since v0.52.0
The slides tree view shows all slides in your presentation with their slide numbers and titles. Each slide is displayed as `{slideNo}. {title}` making it easy to navigate to specific slides.
#### AI/Copilot Integration {#ai-integration}
> Available since v0.52.0
The extension provides Language Model Tools that allow VSCode's Copilot and other AI assistants to interact with your Slidev project. The following tools are available:
- `slidev_getActiveSlide` - Get information about the current active slide and project
- `slidev_getSlideContent` - Retrieve the content of a specific slide by number
- `slidev_getAllSlideTitles` - List all slide titles in the presentation
- `slidev_findSlideNoByTitle` - Find a slide number by its title
- `slidev_listEntries` - List all loaded Slidev project entries
- `slidev_getPreviewPort` - Get the preview server port for a project
- `slidev_chooseEntry` - Switch the active Slidev entry
These tools enable AI assistants to help you navigate, edit, and understand your slides more effectively.
================================================
FILE: docs/features/zoom-slide.md
================================================
---
relates:
- guide/faq#adjust-size
- features/canvas-size
- features/transform-component
tags: [layout]
description: |
Zoom the content of a slide to a specific scale.
---
# Zoom Slides
You may find some slides in your presentation too spacious or too crowded. Slidev provides a `zoom` option for each slide that allows you to scale the content of a slide:
```md
---
zoom: 0.8
---
# A Slide with lots of content
---
# Other slides aren't affected
```
To scale all the slides in your presentation, you can set the slide canvas size:
To adjust the size of some elements on your slides, you can use the `Transform` component:
================================================
FILE: docs/guide/animations.md
================================================
---
outline: deep
---
# Animation
Animation is an essential part of slide presentations. Slidev provides a variety of ways to animate your slides, from the simple to the complex. This guide will show you how to use them effectively.
## Click Animation {#click-animation}
A "**click**" can be considered as the unit of animation steps in slides. A slide can have one or more clicks, and each click can trigger one or more animations - for example, revealing or hiding elements.
> [!NOTE]
> Since v0.48.0, we've rewritten the click animations system with much more consistent behaviors. It might change the behaviors of your existing slides in edge cases. While this page is showing the new click system, you can find more details about the refactor in [#1279](https://github.com/slidevjs/slidev/pull/1279).
### `v-click` {#v-click}
To apply show/hide "click animations" for elements, you can use the `` component or the `v-click` directive.
```md
Hello World!
Hey!
```
### `v-after` {#v-after}
`v-after` will turn the element visible when the previous `v-click` is triggered.
```md
Hello
World
```
When you press "next", both `Hello` and `World` will show up together.
### Hide after clicking {#hide-after-clicking}
Add a `.hide` modifier to `v-click` or `v-after` directives to make elements invisible after clicking, instead of showing up.
```md
Visible after 1 click
Hidden after 2 clicks
Hidden after 2 clicks
```
For the components, you can use the `hide` prop to achieve the same effect:
```md
Visible after 1 click Hidden after 2 clicks Also hidden after 2 clicks
```
### `v-clicks` {#v-clicks}
`v-clicks` is only provided as a component. It's a shorthand to apply the `v-click` directive to all its child elements. It is especially useful when working with lists and tables.
```md
- Item 1
- Item 2
- Item 3
```
An item will become visible each time you click "next".
It accepts a `depth` prop for nested list:
```md
- Item 1
- Item 1.1
- Item 1.2
- Item 2
- Item 2.1
- Item 2.2
```
Also, you can use the `every` prop to specify the number of items to show after each click:
```md
- Item 1.1
- Item 1.2
- Item 2.1
- Item 2.2
```
### Positioning {#positioning}
By default, the clicking animations are triggered one by one. You can customize the animation "position" of elements by using the `at` prop or the `v-click` directive with value.
Like the CSS layout system, click-animated elements can be "relative" or "absolute":
#### Relative Position {#relative-position}
This actual position of relative elements is calculated based on the previous relative elements:
````md
visible after 1 click
visible after 3 clicks
hidden after 2 clicks
```js {none|1|2}{at:'+5'}
1 // highlighted after 7 clicks
2 // highlighted after 8 clicks
```
````
> [!NOTE]
> The default value of `v-click` is `'+1'` when you don't specify it.
In fact, `v-after` are just shortcuts for `v-click` with `at` prop:
```md
```
::: tip `at` prop value format
Only string values starting with `'+'` or `'-'` like `'+1'` are treated as relative positions:
| Value | Kind |
| -------------- | -------- |
| `'-1'`, `'+1'` | Relative |
| `+1` === `1` | Absolute |
| `'1'` | Absolute |
So don't forget the single quotes for the relative values.
:::
#### Absolute Position {#absolute-position}
The given value is the exact click count to trigger this animation:
````md
visible after 3 clicks
visible after 2 clicks
hidden after 1 click
```js {none|1|2}{at:3}
1 // highlighted after 3 clicks
2 // highlighted after 4 clicks
```
````
#### Mixed Case {#mixed-case}
You can mix the absolute and relative positions:
```md
visible after 1 click
visible after 3 clicks
visible after 2 click
visible after 1 click
visible after 4 clicks
```
The following example synchronizes the highlighting of the two code blocks:
````md {1,6}
```js {1|2}{at:1}
1 + 1
'a' + 'b'
```
```js {1|2}{at:1}
= 2
= 'ab'
```
````
### Enter & Leave {#enter-leave}
You can also specify the enter and leave index for the `v-click` directive by passing an array. The end index is exclusive.
```md
This will be hidden at click 2 and 3 (and shown otherwise).
This will be shown only at click 2 (and hidden otherwise).
```
You can also use `v-switch` to achieve the same effect:
```md
show at click 1, hide at click 2.
show at click 2, hide at click 5.
show at click 5, hide at click 7.
```
See [`VSwitch` Component](/builtin/components#vswitch) for more details.
### Custom Total Clicks Count {#total}
By default, Slidev automatically calculates how many clicks are required before going to the next slide. You can override this via the `clicks` frontmatter option:
```yaml
---
# 10 clicks in this slide, before going to the next slide
clicks: 10
---
```
### Element Transitions {#element-transitions}
When you apply the `v-click` directive to your elements, it will attach the class name `slidev-vclick-target` to it. When the elements are hidden, the class name `slidev-vclick-hidden` will also be attached. For example:
```html
Text
```
After a click, it may become:
```html
Text
```
By default, a subtle opacity transition is applied to those classes:
```css
/* below shows the default style */
.slidev-vclick-target {
transition: opacity 100ms ease;
}
.slidev-vclick-hidden {
opacity: 0;
pointer-events: none;
}
```
You can override them to customize the transition effects in your custom stylesheets. For example, you can achieve the scaling up transitions by:
```css
/* styles.css */
.slidev-vclick-target {
transition: all 500ms ease;
}
.slidev-vclick-hidden {
transform: scale(0);
}
```
To specify animations for only certain slides or layouts:
```scss
.slidev-page-7,
.slidev-layout.my-custom-layout {
.slidev-vclick-target {
transition: all 500ms ease;
}
.slidev-vclick-hidden {
transform: scale(0);
}
}
```
Learn more about [customizing styles](/custom/directory-structure#style).
## Motion {#motion}
Slidev has [@vueuse/motion](https://motion.vueuse.org/) built-in. You can use the `v-motion` directive to any elements to apply motion to them. For example
```html
Slidev
```
The text `Slidev` will move from `-80px` to its original position when entering the slide. When leaving, it will move to `80px`.
> Before v0.48.9, you need to add `preload: false` to the slide's frontmatter to enable motion.
### Motion with Clicks {#motion-with-clicks}
> Available since v0.48.9
You can also trigger the motion by clicks:
```html
Slidev
```
Or combine `v-click` with `v-motion`:
```html
Shown at click 2 and hidden at click 4.
```
The meanings of variants:
- `initial`: When `currentPage < thisPage`, or `v-click` hides the current element because `$clicks` is too small.
- `enter`: When `currentPage === thisPage`, and `v-click` shows the element. _Priority: lowest_
- `click-x`: `x` is a number representing the **absolute** click num. The variant will take effect if `$clicks >= x`. _Priority: `x`_
- `click-x-y`: The variant will take effect if `x <= $clicks < y`. _Priority: `x`_
- `leave`: `currentPage > thisPage`, or `v-click` hides the current element because `$clicks` is too large.
The variants will be combined according to the priority defined above.
::: warning
Due to a Vue internal [bug](https://github.com/vuejs/core/issues/10295), currently **only** `v-click` applied to the same element as `v-motion` can control the motion animation. As a workaround, you can use something like `v-if="3 < $clicks"` to achieve the same effect.
:::
Learn more: [Demo](https://sli.dev/demo/starter/10) | [@vueuse/motion](https://motion.vueuse.org/) | [v-motion](https://motion.vueuse.org/features/directive-usage) | [Presets](https://motion.vueuse.org/features/presets)
## Slide Transitions {#slide-transitions}
Slidev supports slide transitions out of the box. You can enable it by setting the `transition` frontmatter option:
```md
---
transition: slide-left
---
```
This will give you a nice sliding effects on slide switching. Setting it in the headmatter will apply this to all slides. You can also set different transitions per slide in frontmatters.
### Builtin Transitions {#builtin-transitions}
- `fade` - Crossfade in/out
- `fade-out` - Fade out and then fade in
- `slide-left` - Slides to the left (slide to right when going backward)
- `slide-right` - Slides to the right (slide to left when going backward)
- `slide-up` - Slides to the top (slide to bottom when going backward)
- `slide-down` - Slides to the bottom (slide to top when going backward)
- `view-transition` - Via the view transitions API
### View Transition API {#view-transitions}
The View Transitions API provides a mechanism for easily creating animated transitions between different DOM states. Learn more about it in [View Transitions API - MDN Web Docs](https://developer.mozilla.org/en-US/docs/Web/API/View_Transitions_API).
:::warning
Experimental: This is not supported by all browsers. Check the [Browser compatibility table](https://developer.mozilla.org/en-US/docs/Web/API/View_Transitions_API#browser_compatibility) carefully before using this.
:::
You can use the `view-transition-name` CSS property to name view transitions, which creates connections between different page elements and smooth transitions when switching slides.
You can enable [Comark Syntax](/guide/syntax#comark-syntax) support to conveniently name view-transitions:
```md
---
transition: view-transition
comark: true
---
# View Transition {.inline-block.view-transition-title}
---
# View Transition {.inline-block.view-transition-title}
```
### Custom Transitions {#custom-transitions}
Slidev's slide transitions are powered by [Vue Transition](https://vuejs.org/guide/built-ins/transition.html). You can provide your custom transitions by:
```md
---
transition: my-transition
---
```
and then in your custom stylesheets:
```css
.my-transition-enter-active,
.my-transition-leave-active {
transition: opacity 0.5s ease;
}
.my-transition-enter-from,
.my-transition-leave-to {
opacity: 0;
}
```
Learn more about how it works in [Vue Transition](https://vuejs.org/guide/built-ins/transition.html).
### Forward & Backward Transitions {#forward-backward-transitions}
You can specify different transitions for forward and backward navigation using `|` as a separator in the transition name:
```md
---
transition: go-forward | go-backward
---
```
With this, when you go from slide 1 to slide 2, the `go-forward` transition will be applied. When you go from slide 2 to slide 1, the `go-backward` transition will be applied.
### Advanced Usage {#advanced-usage}
The `transition` field accepts an option that will passed to the [``](https://vuejs.org/api/built-in-components.html#transition) component. For example:
```md
---
transition:
name: my-transition
enterFromClass: custom-enter-from
enterActiveClass: custom-enter-active
---
```
================================================
FILE: docs/guide/component.md
================================================
# Components in Slides
One of the most powerful features of Slidev is the ability to use Vue components directly in your slides. This allows you to create interactive and dynamic content with ease.
## Using Components {#use}
With the help of [`unplugin-vue-components`](https://github.com/unplugin/unplugin-vue-components), Slidev allows you to use Vue components directly in your slides without importing them manually:
```md
# My Slide
```
The components come from:
- Built-in components. See [Built-in Components](../builtin/components) for reference.
- Provided by the theme and addons. See .
- Custom components in the `components` directory. See the next section.
## Writing Components {#write}
To create a custom component, simply create a new Vue file in the `components` directory:
```bash
your-slidev/
├── ...
├── slides.md
└── components/
├── ...
└── MyComponent.vue
```
Refer to the [Vue documentation](https://vuejs.org/guide/essentials/component-basics.html) for how to write Vue components.
You can also to reuse and share your components with others.
================================================
FILE: docs/guide/exporting.md
================================================
---
outline: deep
---
# Exporting
Usually the slides are displayed in a web browser, but you can also export them to PDF, PPTX, PNG, or Markdown files for sharing or printing. This feature is available through the CLI command [`slidev export`](../builtin/cli#export).
However, interactive features in your slides may not be available in the exported files. You can build and host your slides as a web application to keep the interactivity. See [Building and Hosting](./hosting) for more information.
## The Browser Exporter Recommended {#browser}
> Available since v0.50.0-beta.11
Slidev provides a UI in the browser for exporting your slides. You can access it by clicking the "Export" button in "More options" menu in the [navigation bar](./ui#navigation-bar), or go to `http://localhost:/export` directly.
In the UI, you can export the slides as PDF, or capture the slides as images and download them as a PPTX or zip file.
Note that browsers other than **modern Chromium-based browsers** may not work well with the exporting UI. If you encounter any issues, please try use the CLI instead.
> The following content of this page is for the CLI only.
## The CLI {#cli}
Exporting to PDF, PPTX, or PNG relies on [Playwright](https://playwright.dev) for rendering the slides. Therefore [`playwright-chromium`](https://npmjs.com/package/playwright-chromium) is required to be installed in your project:
::: code-group
```bash [pnpm]
$ pnpm add -D playwright-chromium
```
```bash [npm]
$ npm i -D playwright-chromium
```
```bash [yarn]
$ yarn add -D playwright-chromium
```
```bash [bun]
$ bun add -D playwright-chromium
```
```bash [deno]
$ deno add -D npm:playwright-chromium
```
:::
## Formats
### PDF
After installing `playwright-chromium` as described above, you can export your slides to PDF using the following command:
```bash
$ slidev export
```
By default, the PDF will be placed at `./slides-export.pdf`.
### PPTX
Slidev can also export your slides as a PPTX file:
```bash
$ slidev export --format pptx
```
Note that all the slides in the PPTX file will be exported as images, so the text will not be selectable. Presenter notes will be conveyed into the PPTX file on a per-slide basis.
In this mode, the `--with-clicks` option is enabled by default. To disable it, pass `--with-clicks false`.
### PNGs and Markdown
When passing in the `--format png` option, Slidev will export PNG images for each slide instead of a PDF:
```bash
$ slidev export --format png
```
You can also compile a markdown file composed of compiled png using `--format md`:
```bash
$ slidev export --format md
```
## Options
Here are some common options you can use with the `slidev export` command. For a full list of options, see the [CLI documentation](../builtin/cli#export).
### Export Clicks Steps
By default, Slidev exports one page per slide with clicks animations disabled. If you want to export slides with multiple steps into multiple pages, pass the `--with-clicks` option:
```bash
$ slidev export --with-clicks
```
### Output Filename
You can specify the output filename with the `--output` option:
```bash
$ slidev export --output my-pdf-export
```
Or in the headmatter configuration:
```yaml
---
exportFilename: my-pdf-export
---
```
### Export with Range
By default, all slides in the presentation are exported. If you want to export a specific slide or a range of slides you can set the `--range` option and specify which slides you would like to export:
```bash
$ slidev export --range 1,6-8,10
```
This option accepts both specific slide numbers and ranges. The example above would export slides 1,6,7,8 and 10.
### Multiple Exports
You can also export multiple slides at once:
```bash
$ slidev export slides1.md slides2.md
```
Or (only available in certain shells):
```bash
$ slidev export *.md
```
In this case, each input file will generate its own PDF file.
### Dark Mode
In case you want to export your slides using the dark version of the theme, use the `--dark` option:
```bash
$ slidev export --dark
```
### Timeouts
For big presentations, you might want to increase the Playwright timeout with `--timeout`:
```bash
$ slidev export --timeout 60000
```
### Wait
Some parts of your slides may require a longer time to render. You can use the `--wait` option to have an extra delay before exporting:
```bash
$ slidev export --wait 10000
```
There is also a `--wait-until` option to wait for a state before exporting each slide. If you keep encountering timeout issues, you can try setting this option:
```bash
$ slidev export --wait-until none
```
Possible values:
- `'networkidle'` - (_default_) consider operation to be finished when there are no network connections for at least `500` ms. This is the safest, but may cause timeouts.
- `'domcontentloaded'` - consider operation to be finished when the `DOMContentLoaded` event is fired.
- `'load'` - consider operation to be finished when the `load` event is fired.
- `'none'` - do not wait for any event.
::: warning
When specifying values other than `'networkidle'`, please make sure the printed slides are complete and correct. If some contents are missing, you may need to use the `--wait` option.
:::
### Executable Path
Chromium may miss some features like codecs that are required to decode some videos. You can set the browser executable path for Playwright to your Chrome or Edge using `--executable-path`:
```bash
$ slidev export --executable-path [path_to_chromium]
```
### PDF Outline
> Available since v0.36.10
You can generate the PDF outline by passing the `--with-toc` option:
```bash
$ slidev export --with-toc
```
### Omit Background
When exporting to PNGs, you can remove the default browser background by passing `--omit-background`:
```bash
$ slidev export --omit-background
```
The default browser background is the white background visible on all browser windows and is different than other backgrounds applied throughout the application using CSS styling. [See Playwright docs](https://playwright.dev/docs/api/class-page#page-screenshot-option-omit-background). You will then need to apply additional CSS styling to the application to reveal the transparency.
Here is a basic example that covers all backgrounds in the application:
```css
* {
background: transparent !important;
}
```
## Troubleshooting
### Missing Content or Animation not Finished
If you find that some content is missing or the animations are not finished in the exported PDF, you can try adding a wait time before exporting each slide:
```bash
$ slidev export --wait 1000
```
### Broken Emojis
If the PDF or PNG are missing Emojis, you are likely missing required fonts (such as. e.g. [Google's _Noto Emoji_](https://fonts.google.com/noto/specimen/Noto+Emoji)) in your environment.
This can affect e.g. CI/CD-like in-container sort of Linux environments. It can be fixed e.g. like this:
```bash
$ curl -L --output NotoColorEmoji.ttf https://github.com/googlefonts/noto-emoji/raw/main/fonts/NotoColorEmoji.ttf
$ sudo mv NotoColorEmoji.ttf /usr/local/share/fonts/
$ fc-cache -fv
```
### Wrong Context in Global Layers
See the tip in https://sli.dev/features/global-layers.
================================================
FILE: docs/guide/faq.md
================================================
---
outline: deep
---
# FAQ
## Assets Handling {#assets-handling}
You may use static assets like images and videos in your slides. Since Slidev is based on Vite, you can import them directly in your markdown files.
URLs that can be statically analyzed as assets can use relative paths:
```md

```
In the above case, the URLs will be resolved to `/BASE_URL/assets/image.png` after build.
However, relative paths in frontmatter and other components will be broken after build:
```md
---
background: ./image.png # Broken after build
---
```
In the above case, the URLs are not statically analyzable and will be preserved as-is, which will result in 404 errors after build.
To solve this, you can place these assets in the [public folder](../custom/directory-structure#public) and use an absolute path to import them:
```md
---
background: /image.png
---
```
For more details, refer to [Vite's documentation](https://vitejs.dev/guide/assets.html).
## Positioning {#positioning}
Since Slidev is web-based, CSS is the primary way to position elements. Here are some useful tips for position elements:
### Grids And Flexboxes
You can use CSS Grids to create complex layouts:
::: code-group
```md [Two columns]
The first column
The second column
```
```md [Complex case]
The first column (200px)
The second column (auto fit)
The third column (10% width to parent container)
```
:::
And use Flexboxes to create more responsive layouts:
::: code-group
```md [Horizontal]
First block
Second block
```
```md [Vertical]
Centered content
```
:::
Learn more: [CSS Grids](https://css-tricks.com/snippets/css/complete-guide-grid/), [flexboxes](https://css-tricks.com/snippets/css/a-guide-to-flexbox/), or even [Masonry](https://css-tricks.com/native-css-masonry-layout-in-css-grid/).
### Absolute Position
You can use UnoCSS to position elements absolutely:
```md
This is a left-bottom aligned footer
```
Or use the draggable elements feature:
## Adjust Sizes {#adjust-size}
- Adjust all slides's size:
- Adjust several slides' size:
- Adjust some elements' size:
================================================
FILE: docs/guide/global-context.md
================================================
# Global Context
Slidev injects several global context values for advanced navigation controls.
## Direct Usage {#direct-usage}
You can access them directly in your slides or components:
```md [slides.md]
# Page 1
Current page is: {{ $nav.currentPage }}
```
```vue [Foo.vue]
Title: {{ $slidev.configs.title }}
```
## Composable Usage {#composable-usage}
> Available since v0.48.0
If you want to get the context programmatically (also type-safely), you can import composables from `@slidev/client`:
```vue
```
> [!NOTE]
> Previously, you might see the usage of importing nested modules like `import { isDark } from '@slidev/client/logic/dark.ts'`, this is **NOT RECOMMENDED** as they are internal implementation details and may change in the future. Always use the public APIs from `@slidev/client` if possible.
::: warning
When the `useSlideContext` composable is used in a file, the automatic injection of `$slidev` will be disabled. You need to manually get the `$slidev` object to the `useSlideContext` function.
:::
## Properties {#properties}
### `$slidev` {#slidev}
The global context object.
### `$frontmatter` {#frontmatter}
The frontmatter object of the current slide. Note that this is empty for components out of the slides like .
### `$clicks` {#clicks}
`$clicks` hold the number of clicks on the current slide. Can be used conditionally to show different content on clicks.
```html
Content
```
See the guide for more information.
### `$nav` {#nav}
A reactive object holding the properties and controls of the slide navigation. For examples:
```js
$nav.next() // go next step
$nav.nextSlide() // go next slide (skip clicks)
$nav.go(10) // go slide #10
$nav.currentPage // current slide number
$nav.currentLayout // current layout name
```
For more properties available, refer to the [`SlidevContextNav` interface](https://github.com/slidevjs/slidev/blob/main/packages/client/composables/useNav.ts).
### `$page` {#page}
`$page` holds the number of the current page, 1-indexed.
```md
Page: {{ $page }}
Is current page active: {{ $page === $nav.currentPage }}
```
> [!Note] > `$nav.clicks` is a global state while `$clicks` is the local clicks number for each slide.
### `$renderContext` {#render-context}
`$renderContext` holds the current render context, which can be `slide`, `overview`, `presenter` or `previewNext`
```md
This content will only be rendered in main slides view
```
You can also use the [`` component](../builtin/components#renderwhen).
### `$slidev.configs` {#configs}
A reactive object holding the configurations for the slide project. For example:
```md
---
title: My First Slidev!
---
# Page 1
---
# Any Page
{{ $slidev.configs.title }} // 'My First Slidev!'
```
### `$slidev.themeConfigs` {#theme-configs}
A reactive object holding the parsed theme configurations:
```yaml
---
title: My First Slidev!
themeConfig:
primary: '#213435'
---
```
Then the theme can access the primary color like:
```md
{{ $slidev.themeConfigs.primary }} // '#213435'
```
## Types {#types}
If you want to get a type programmatically, you can import types like `TocItem` from `@slidev/types`:
```vue
```
================================================
FILE: docs/guide/hosting.md
================================================
---
outline: deep
---
# Building and Hosting
Slidev is designed to run as a web server when you are editing or presenting your slides. However, after the presentation, you may still want to share your **interactive** slides with others. This guide will show you how to build and host your slides.
## Build as a SPA {#spa}
You can build the slides into a static [Single-page application (SPA)](https://developer.mozilla.org/en-US/docs/Glossary/SPA) via the following command:
```bash
$ slidev build
```
By default, the generated files are placed in the `dist` folder. You can test the built version of you slides by running: `npx vite preview` or any other static server.
### Base Path {#base}
To deploy your slides under sub-routes, you need to pass the `--base` option. The `--base` path **must begin and end with a slash `/`**. For example:
```bash
$ slidev build --base /talks/my-cool-talk/
```
Refer to [Vite's documentation](https://vitejs.dev/guide/build.html#public-base-path) for more details.
### Output directory {#output-directory}
You can change the output directory using `--out`.
```bash
$ slidev build --out my-build-folder
```
### Remove speaker notes {#without-notes}
If you are sharing the built slides publicly and don't want to include your speaker notes, run the build with `--without-notes`:
```bash
$ slidev build --without-notes
```
### Multiple Builds {#multiple-builds}
You can build multiple slide decks in one go by passing multiple markdown files as arguments:
```bash
$ slidev build slides1.md slides2.md
```
Or if your shell supports it, you can use a glob pattern:
```bash
$ slidev build *.md
```
In this case, each input file will generate a folder containing the build in the output directory.
### Examples {#examples}
Here are a few examples of the exported SPA:
- [Demo Slides](https://sli.dev/demo/starter)
- [Composable Vue](https://talks.antfu.me/2021/composable-vue) by [Anthony Fu](https://github.com/antfu)
- More in [Showcases](../resources/showcases)
### Options {#options}
## Hosting {#hosting}
We recommend using `npm init slidev@latest` to scaffold your project, which contains the necessary configuration files for hosting services out-of-the-box.
### GitHub Pages {#github-pages}
To deploy your slides on [GitHub Pages](https://pages.github.com/) via GitHub Actions, follow these steps:
1. In your repository, go to `Settings` > `Pages`. Under `Build and deployment`, select `GitHub Actions`. (Do not choose `Deploy from a branch` and upload the `dist` directory, which is not recommended.)
2. Create `.github/workflows/deploy.yml` with the following content to deploy your slides to GitHub Pages via GitHub Actions.
::: details deploy.yml
```yaml
name: Deploy pages
on:
workflow_dispatch:
push:
branches: [main]
permissions:
contents: read
pages: write
id-token: write
concurrency:
group: pages
cancel-in-progress: false
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: 'lts/*'
- name: Setup @antfu/ni
run: npm i -g @antfu/ni
- name: Install dependencies
run: nci
- name: Build
run: nr build --base /${{github.event.repository.name}}/
- name: Setup Pages
uses: actions/configure-pages@v4
- uses: actions/upload-pages-artifact@v3
with:
path: dist
deploy:
environment:
name: github-pages
url: ${{ steps.deployment.outputs.page_url }}
needs: build
runs-on: ubuntu-latest
name: Deploy
steps:
- name: Deploy to GitHub Pages
id: deployment
uses: actions/deploy-pages@v4
```
:::
3. Commit and push the changes to your repository. The GitHub Actions workflow will automatically deploy your slides to GitHub Pages every time you push to the `main` branch.
4. You can access your slides at `https://.github.io//`.
### Netlify
Create `netlify.toml` in your project root with the following content:
::: details netlify.toml
```toml
[build]
publish = 'dist'
command = 'npm run build'
[build.environment]
NODE_VERSION = '20'
[[redirects]]
from = '/*'
to = '/index.html'
status = 200
```
:::
Then go to your [Netlify dashboard](https://netlify.com/) and create a new site with the repository.
### Vercel
Create `vercel.json` in your project root with the following content:
::: details vercel.json
```json
{
"rewrites": [
{ "source": "/(.*)", "destination": "/index.html" }
]
}
```
:::
Then go to your [Vercel dashboard](https://vercel.com/) and create a new site with the repository.
### Zephyr Cloud {#zephyr-cloud}
To deploy your Slidev deck on [Zephyr Cloud](https://zephyr-cloud.io/), you can add Zephyr support to an existing Slidev project with:
```bash
npx with-zephyr@latest
```
This codemod detects your bundler (Slidev uses Vite) and updates your config for Zephyr Cloud.
After setup, run your normal build command, for example:
```bash
npm run build
```
When the build runs with Zephyr enabled, your app is deployed and Zephyr Cloud returns a preview URL.
::: info
Zephyr Cloud is a bit different from most hosting providers: every `build` run triggers a deployment.
:::
### Host on Docker {#docker}
If you need a rapid way to run a presentation with containers, you can use the prebuilt [docker image](https://hub.docker.com/r/tangramor/slidev) maintained by [tangramor](https://github.com/tangramor), or build your own.
::: details Use the Docker Image
Just run the following command in your work folder:
```bash
docker run --name slidev --rm -it \
--user node \
-v ${PWD}:/slidev \
-p 3030:3030 \
-e NPM_MIRROR="https://registry.npmmirror.com" \
tangramor/slidev:latest
```
**_Note_**: You can use `NPM_MIRROR` to specify a npm mirror to speed up the installation process.
If your work folder is empty, it will generate a template `slides.md` and other related files under your work folder, and launch the server on port `3030`.
You can access your slides from `http://localhost:3030/`
To create an Docker Image for your slides, you can use the following Dockerfile:
```Dockerfile
FROM tangramor/slidev:latest
ADD . /slidev
```
Create the docker image: `docker build -t myslides .`
And run the container: `docker run --name myslides --rm --user node -p 3030:3030 myslides`
You can visit your slides at `http://localhost:3030/`
:::
================================================
FILE: docs/guide/index.md
================================================
---
outline: deep
---
# Getting Started
Slidev (slide + dev, **/slaɪdɪv/**) is a web-based slides maker and presenter. It's designed for developers to focus on writing content in Markdown. With the power of web technologies like Vue, you are able to deliver pixel-perfect designs with interactive demos to your presentation.
::: tip
You can learn more about the rationale behind this project in .
:::
## Create Slides
### Try it Online
Start Slidev right in your browser with StackBlitz: [sli.dev/new](https://sli.dev/new)
### Create Locally
> Requires [Node.js](https://nodejs.org) >= 18.0 installed.
Run the following command to create a new Slidev project locally:
::: code-group
```bash [pnpm]
# If you haven't installed pnpm
npm i -g pnpm
pnpm create slidev
```
```bash [npm]
# Not recommended -
# NPM will download the packages each time you create a new project,
# which is slow and takes up a lot of space
npm init slidev@latest
```
```bash [yarn]
yarn create slidev
```
```bash [bun]
bun create slidev
```
```bash [deno]
deno init --npm slidev
```
:::
Follow the prompts to start your slides project. The slides content is in `slides.md`, which initially includes demos of most the Slidev features. For more information about the Markdown syntax, please check .
:::: details Single file usage (not recommended)
If you prefer to have a single Markdown file as your slides, you can install the Slidev CLI globally:
::: code-group
```bash [pnpm]
pnpm i -g @slidev/cli
```
```bash [npm]
npm i -g @slidev/cli
```
```bash [yarn]
yarn global add @slidev/cli
```
```bash [bun]
bun i -g @slidev/cli
```
```bash [deno]
deno i -g npm:@slidev/cli
```
:::
Then, you can create and start a single file slides via:
```bash
slidev slides.md
```
::::
## Basic Commands
Slidev provides a set of commands in its CLI. Here are some common ones:
- `slidev` - Start the dev server. See [the dev command](../builtin/cli#dev).
- `slidev export` - Export the slides to PDF, PPTX, or PNGs. See .
- `slidev build` - Build the slides as a static web application. See .
- `slidev format` - Format the slides. See [the format command](../builtin/cli#format).
- `slidev --help` - Show the help message
To run these commands, you can add them to your `package.json` scripts (which has been done for you if the project was created via `npm init slidev`):
```json [package.json]
{
"scripts": {
"dev": "slidev --open",
"build": "slidev build",
"export": "slidev export"
}
}
```
Then, you can simply run `npm run dev`, `npm run build`, and `npm run export`.
For more information about the CLI, please check the [CLI guide](../builtin/cli).
## Setup Your Editor {#editor}
Since Slidev uses Markdown as the source entry, you can use any editor you prefer to create your slides. We also provide tools to help you edit you slides more conveniently:
## Join the Community
It's recommended to join our official [Discord Server](https://chat.sli.dev/) to get help, share your slides, or discuss anything about Slidev.
If you're encountering bugs, feel free to open an issue on [GitHub](https://github.com/slidevjs/slidev/issues/new/choose).
## Tech Stack
Slidev is made possible by combining these tools and technologies.
- [Vite](https://vitejs.dev) - An extremely fast frontend tooling
- [Vue 3](https://v3.vuejs.org/) powered [Markdown](https://daringfireball.net/projects/markdown/syntax) - Focus on the content while having the power of HTML and Vue components whenever needed
- [UnoCSS](https://github.com/unocss/unocss) - On-demand utility-first CSS framework, style your slides at ease
- [Shiki](https://github.com/shikijs/shiki), [Monaco Editor](https://github.com/Microsoft/monaco-editor) - First-class code snippets support with live coding capability
- [RecordRTC](https://recordrtc.org) - Built-in recording and camera view
- [VueUse](https://vueuse.org) family - [`@vueuse/core`](https://github.com/vueuse/vueuse), [`@vueuse/head`](https://github.com/vueuse/head), [`@vueuse/motion`](https://github.com/vueuse/motion), etc.
- [Iconify](https://iconify.design/) - Iconsets collection.
- [Drauu](https://github.com/antfu/drauu) - Drawing and annotations support
- [KaTeX](https://katex.org/) - LaTeX math rendering.
- [Mermaid](https://mermaid-js.github.io/mermaid) - Textual Diagrams.
================================================
FILE: docs/guide/layout.md
================================================
# Slide Layout
Layouts in Slidev are used to define the structure for each slide. They are Vue components that wrap the content of the slides.
## Using Layouts {#use}
To use a layout, you can specify it in the frontmatter of the slide:
```md
---
layout: quote
---
A quote from someone
```
By default, the layout of the first slide is `cover`, and the rest are `default`.
The layouts are loaded in the following order, and the last one loaded will override the previous ones:
1. default layouts. See [Built-in Layouts](../builtin/layouts).
2. layouts provided by the theme
3. layouts provided by the addons
4. custom layouts in the `layouts` directory
## Writing Layouts {#write}
================================================
FILE: docs/guide/syntax.md
================================================
---
outline: deep
---
# Syntax Guide
Slidev's slides are written as Markdown files, which are called **Slidev Markdown**s. A presentation has a Slidev Markdown as its entry, which is `./slides.md` by default, but you can change it by passing the file path as an argument to [the CLI commands](../builtin/cli).
In a Slidev Markdown, not only [the basic Markdown features](https://github.com/adam-p/markdown-here/wiki/Markdown-Cheatsheet) can be used as usual, Slidev also provides additional features to enhance your slides. This section covers the syntax introduced by Slidev. Please make sure you know the basic Markdown syntax before reading this guide.
## Slide Separators {#slide-separators}
Use `---` padded with a new line to separate your slides.
````md {5,15}
# Title
Hello, **Slidev**!
---
# Slide 2
Use code blocks for highlighting:
```ts
console.log('Hello, World!')
```
---
# Slide 3
Use UnoCSS classes and Vue components to style and enrich your slides:
````
## Frontmatter & Headmatter {#frontmatter}
At the beginning of each slide, you can add an optional [frontmatter](https://jekyllrb.com/docs/front-matter/) to configure the slide. The first frontmatter block is called **headmatter** and can configure the whole slide deck. The rest are **frontmatters** for individual slides. Texts in the headmatter or the frontmatter should be an object in [YAML](https://www.cloudbees.com/blog/yaml-tutorial-everything-you-need-get-started/) format. For example:
```md {1-4,10-14,26-28}
---
theme: seriph
title: Welcome to Slidev
---
# Slide 1
The frontmatter of this slide is also the headmatter
---
layout: center
background: /background-1.png
class: text-white
---
# Slide 2
A page with the layout `center` and a background image
---
# Slide 3
A page without frontmatter
---
src: ./pages/4.md # This slide only contains a frontmatter
---
---
# Slide 5
```
Configurations you can set are described in the [Slides deck configurations](/custom/#headmatter) and [Per slide configurations](/custom/#frontmatter) sections.
To make the headmatter more readable, you can install the VSCode extension:
Also, there is another possible frontmatter format:
## Notes {#notes}
You can also create presenter notes for each slide. They will show up in for you to reference during presentations.
The comment blocks at the end of each slide are treated as the note of the slide:
```md {9,19-21}
---
layout: cover
---
# Slide 1
This is the cover page.
---
# Slide 2
The second page
```
Basic Markdown and HTML are also supported in notes and will be rendered.
## Code Blocks {#code-block}
One big reason that led to the creation of Slidev was the need to perfectly display code in slides. Consequently, you can use Markdown-flavored code blocks to highlight your code.
````md
```ts
console.log('Hello, World!')
```
````
Slidev has [Shiki](https://github.com/shikijs/shiki) built in as the syntax highlighter. Refer to [Configure Shiki](/custom/config-highlighter) for more details.
More about code blocks:
## LaTeX Blocks {#latex-block}
Slidev supports LaTeX blocks for mathematical and chemical formulas:
## Diagrams {#diagrams}
Slidev supports [Mermaid](https://mermaid.js.org/) and [PlantUML](https://plantuml.com/) for creating diagrams from text:
## Comark Syntax {#comark-syntax}
Comark Syntax is the easiest way to apply styles and classes to elements:
## Scoped CSS {#scoped-css}
You can use scoped CSS to style your slides:
## Importing Slides {#importing-slides}
================================================
FILE: docs/guide/theme-addon.md
================================================
# Theme and Addons
A slides project can have one theme and multiple addons. All of them can provide styles, components, layouts, and other configs to your slides project.
## Use a Theme {#use-theme}
Changing the theme in Slidev is surprisingly easy. All you need to do is to add the `theme` option in your [headmatter](../custom/index#headmatter):
```md
---
theme: seriph
---
# The first slide
```
You can find the list of official themes and community themes in the [Themes Gallery](../resources/theme-gallery).
::: info Theme name convention
- You can also pass a relative or absolute path to a local theme folder, like `../my-theme`
- You can always use the full package name as the theme name
- If the theme is [official](../resources/theme-gallery#official-themes) or is named like `slidev-theme-name`, you can omit the `slidev-theme-` prefix
- For scoped packages like `@org/slidev-theme-name`, the full package name is required
:::
You can start the server and will be prompted to install the theme after a confirmation.
? The theme "@slidev/theme-seriph" was not found in your project, do you want to install it now? › (Y/n)
or install the theme manually via:
```bash
$ npm install @slidev/theme-seriph
```
And that's all, enjoy the new theme! For more details about the usage, you can refer to the theme's README.
## Use an Addon {#use-addon}
Addons are similar to themes, but they are more flexible and can be used to add extra features to your slides project. You can add multiple addons to your project, and they can be used to add extra features to your slides project.
To use an addon, you can add the `addons` option in your [headmatter](../custom/index#headmatter):
```md
---
addons:
- excalidraw
- '@slidev/plugin-notes'
---
```
You can find the list of official addons and community addons in the [Addons Gallery](../resources/addon-gallery).
================================================
FILE: docs/guide/ui.md
================================================
---
outline: deep
---
# User Interface
## Navigation Bar {#navigation-bar}
In Play mode, move your mouse to the bottom left corner of the page, you can see the navigation bar.

> You can extend the navigation bar via .
## Navigation Actions {#navigation-actions}
| Keyboard Shortcut | Button in Navigation Bar | Description |
| ----------------------------------- | ------------------------------------------------------------------------------------- | --------------------------------------------------------------- |
| f | | Toggle fullscreen |
| right / space | | Next animation or slide |
| left | | Previous animation or slide |
| up | - | Previous slide |
| down | - | Next slide |
| o | | Toggle [Quick Overview](#quick-overview) |
| d | | Toggle dark mode |
| - | | Toggle [Camera View](../features/recording#camera-view) |
| - | | Start |
| - | | Enter [Presenter Mode](#presenter-mode) |
| - | | Toggle |
| - | | Enter [Browser Exporter](#exporter) |
| - | | Download PDF. See |
| - | | Show information about the slides |
| - | | More options |
| g | - | Show goto... |
> You can [configure the shortcuts](../custom/config-shortcuts).
## Quick Overview {#quick-overview}
By pressing o or clicking the button in the navigation bar, you can have an overview of your slides so you can jump between them easily.

## Presenter Mode {#presenter-mode}
To enter the presenter mode, you can click the button in the navigation panel, or visit `http://localhost:/presenter`.
When giving a presentation, it's recommended to open two browser windows - one in the play mode for the audience, and another one in the presenter mode for you. Then you can share the first screen to the audience and keep the second screen for yourself.
Whenever you navigate through the slides in the presenter mode, all other opened pages will automatically follow this navigation to stay in sync with the presenter.

### Presenter Layouts {#presenter-layouts}
> Available since v0.50.0
The presenter view offers three different layouts that you can cycle through by clicking the layout toggle button in the navigation bar:
- **Layout 1** (default): Current slide prominently displayed at the top, with notes and next slide preview below
- **Layout 2**: Notes panel on the left, current slide and next slide stacked on the right
- **Layout 3**: Notes and current slide on the left, larger next slide preview on the right
Each layout is optimized for different screen sizes and presentation preferences.
### Screen Mirror {#screen-mirror}
> Available since v0.50.0
In the presenter view, you can switch the main slide area to "Screen Mirror" mode. This allows you to capture and display another monitor or window directly in the presenter view.
Click the "Screen Mirror" option in the presenter view's segment control, then select the screen or window you want to mirror. This is useful when you want to see exactly what your audience sees on the projector or external display (e.g. live coding / live demo).
## Slide Overview {#slides-overview}
> Available since v0.48.0
You can visit an overview of all of your slides by first opening the [Quick Overview panel](#quick-overview) and then clicking the on the top right, or by visiting `http://localhost:/overview` directly.
The overview page gives you a linear list of all your slides, with all of your notes on the side. You can double-click on the notes to edit the notes directly, and drag the clicks sliders to preview the steps in your slides.
## Notes Editor {#notes-editor}
> Available since v0.52.0
Slidev provides a batch notes editor at `http://localhost:/notes-edit` where you can edit notes for all slides in a single text area.
Notes for each slide are separated by `--- #[slide-number]` markers. Changes are automatically saved as you type with debouncing.
This is useful when you want to write or review all your speaker notes in one place without switching between slides.
## Drawing UI {#drawing}
See:
## Recording UI {#recording}
See:
## Browser Exporter {#exporter}
See:
## Settings {#settings}
Click the button in the navigation bar to access additional settings.
### CSS Filters {#css-filters}
> Available since v0.50.0
When presenting on different projectors or displays, colors may appear differently than expected. Slidev provides CSS filter controls to adjust the display in real-time:
- **Invert**: Flip all colors
- **Brightness**: Adjust overall brightness (0.5 - 1.5)
- **Contrast**: Adjust contrast levels (0.5 - 1.5)
- **Saturation**: Adjust color saturation (0.5 - 1.5)
- **Sepia**: Add sepia tone effect
- **Hue Rotate**: Shift all colors by degrees (-180 to 180)
These settings are stored locally and persist across sessions. A dot indicator appears on the settings button when any filter is active.
### Hide Idle Cursor {#hide-idle-cursor}
> Available since v0.50.0
When enabled, the cursor will automatically hide after a period of inactivity during the presentation. This provides a cleaner viewing experience for your audience.
### Slide Scale {#slide-scale}
Choose between "Fit" mode (scales slides to fit the viewport) or "1:1" mode (displays slides at their native resolution).
### Wake Lock {#wake-lock}
When enabled, prevents the screen from dimming or locking during your presentation. Requires browser support for the Wake Lock API.
## Global Layers {#global-layers}
You can add any custom UI below or above your slides for the whole presentation or per-slide:
================================================
FILE: docs/guide/why.md
================================================
---
outline: deep
---
# Why Slidev
There have been lots of feature-rich WYSIWYG slides makers like [Microsoft PowerPoint](https://www.microsoft.com/en-us/microsoft-365/powerpoint) and [Apple Keynote](https://www.apple.com/keynote/) _(see [Comparisons](#comparisons))_. They are intuitive and easy to learn. So why bother making Slidev?
Slidev aims to provide flexibility and interactivity for **developers** to make their presentations much more interesting, expressive, and attractive by using technologies they are familiar with. Slidev is also open source with a strong community.
Slidev is Markdown-based, which helps you **focus on the content**. Slidev is also Web-based, which means **nothing is impossible** - everything you can do in a web app can apply to your slides.
Slidev is also **progressive**. You can start with a super simple Markdown file, and then use the [built-in features](../features/) when you need them without any configuration. There are also [themes and addons](./theme-addon) you can optionally install to enhance your slides.
 {#welcome}
## Features
### 📝 Markdown-based
Slidev uses an extended Markdown format to organize your slides in a single plain text file. This helps you focus on the content while allowing you to use Git and any editor you like.
> Learn more: .
### 🧑💻 Developer Friendly
Slidev provides first-class support for code snippets for developers. It uses [Shiki](https://github.com/shikijs/shiki) to get the most accurate syntax highlighting. Slidev also supports and . These make Slidev the best choice for tech talks.
### 🎨 Themable
Themes for Slidev can be shared via npm packages. You apply a theme within one line of code.
Check out the [Theme Gallery](../resources/theme-gallery) for the beautiful themes made by the official team and the community.
### ⚡ Fast
Every change you make in the editor will be updated to your slides in the browser **instantly** without reloading, thanks to [Vite's HMR feature](https://vitejs.dev/guide/features.html#hot-module-replacement).
### 🤹 Interactive & Expressive
You can write Vue components and use them in your slides, which you can then interact with during the presentation to express your idea in a more interesting and intuitive way.
Slidev also has built-in support of , which empowers you to do live coding in your presentation with auto-completion and hover messages.
### 🎥 Recording Support
Slidev provides built-in recording and camera view. You can share your presentation with your camera view inside, or record and save your screen and camera separately.
> Learn more: .
### 📤 Portable
You can export your slides into PDF, PPTX, PNGs, or even a single-page application (SPA) via a single command. Then you can share or host it anywhere you like.
> Learn more: and .
### 🛠 Hackable
Because Slidev is web-based, everything that can be done in a normal web app can be applied to your slides. For example, WebGL, API requests, iframes, or even live sharing. It's up to your imagination!
> Learn more: [Customization](../custom/).
## Comparisons
::: details Slidev vs. Microsoft PowerPoint / Apple Keynote
[Microsoft PowerPoint](https://www.microsoft.com/en-us/microsoft-365/powerpoint) and [Apple Keynote](https://www.apple.com/keynote/) are feature-rich WYSIWYG slides makers. They are intuitive and easy to learn, which makes them one of the best choices for non-developers.
Compared to them, Slidev has the following advantages:
- Developer-friendly: Code snippets are first-class citizens in Slidev.
- Markdown-based: Focus on the content, and version control your slides with Git.
- Web-based: Everything you can do in a web app can apply to your slides.
- Hackable: Customize anything you like with web technologies.
- Open source: Slidev is completely open source, and has a strong community.
:::
::: details Slidev vs. Reveal.js
[Reveal.js](https://revealjs.com/) is a popular HTML presentation framework. It is also open source and supports Markdown.
Compared to Reveal.js, Slidev has the following advantages:
- More concise: Slidev uses an extended Markdown format, while Reveal.js encourages you to write HTML to organize your slides.
- Vue support: You can use Vue components in Slidev to make your slides interactive.
- Vite-based: Slidev is built on top of Vite, which provides instant HMR and flexible plugin API.
- Atomatic CSS: You can [UnoCSS](https://unocss.dev/) out of the box to style your slides.
:::
::: details Slidev vs. Marp
[Marp](https://marp.app/) is a Markdown presentation tool that focuses on simplicity and portability. It is also open source and supports Markdown.
Compared to Marp, Slidev has the following advantages:
- The same simplicity: Slidev's slides can start as simple as Marp's.
- More features: Slidev supports many features that Marp doesn't.
- Vue support: You can use Vue components in Slidev to make your slides interactive.
- Vite-based: Slidev is built on top of Vite, which provides instant HMR and flexible plugin API.
- Atomatic CSS: You can [UnoCSS](https://unocss.dev/) out of the box to style your slides.
:::
## Give it a Try
Playing around with Slidev will tell you more than thousands of words. Check the guide to create your first Slidev project in one click or one command.
Or you can have a quick preview of it:
================================================
FILE: docs/guide/work-with-ai.md
================================================
# Work with AI
Thanks to Slidev being markdown-based, it works great with AI coding agents.
## Skills
Slidev provides official [skills](https://code.claude.com/docs/en/skills) for AI coding agents, enabling them to understand Slidev's syntax, features, and best practices when helping you create presentations.
### Installation
Install the Slidev skill to your AI coding agent:
```bash
npx skills add slidevjs/slidev
```
The source code of the skill is [here](https://github.com/slidevjs/slidev/tree/main/skills/slidev).
### Example Prompts
Once installed, you can ask agents to help with various Slidev tasks:
```
Create a Slidev presentation about TypeScript generics with code examples
```
```
Add a two-column slide with code on the left and explanation on the right
```
```
Set up click animations to reveal bullet points one by one
```
```
Configure the presentation for PDF export with speaker notes
```
### What's Included
The Slidev skill provides knowledge about:
- Markdown syntax, slide separators, and frontmatter
- Click animations and transitions
- Code highlighting, Monaco editor, and magic-move
- Diagrams (Mermaid, PlantUML) and LaTeX math
- Built-in layouts and components
- Exporting and hosting options
## VS Code Extension
The provides Language Model Tools that allow VS Code's Copilot and other AI assistants to interact with your Slidev project directly. These tools enable AI to:
- Get information about the active slide and project
- Retrieve content of specific slides
- List and search slides by title
- Navigate between slides
See for more details.
================================================
FILE: docs/guide/write-addon.md
================================================
# Writing Addons
> Please read and first.
Each slides project can only have one theme, but can have multiple addons.
## Capability
Theoretically, all the capabilities of a theme can be done in an addon. However, an addon is more like a plugin that extends the functionalities of Slidev.
It's recommended to implement one or more of the following points in an addon:
- Provide custom components
- Provide _new_ layouts
- Provide new code snippets
- Provide new code runners
- Configure tools like UnoCSS, Vite, etc.
However, the following points are **not** recommended to be done in an addon, and may be better [implemented as a theme](./write-theme):
- Wildcard global styles
- Overriding existing layouts
- Overriding configurations
- Other things that may be incompatible with the theme and other addons
An addon can also specify its required Slidev version in the same way as themes.
## Previewing
The same as themes, you can preview your addon via a `./slides.md` like this:
```md [slides.md]
---
addons:
- ./
---
```
## Publishing
When publishing the addon, non-JS files like `.vue` and `.ts` files can be published directly without compiling. Slidev will automatically compile them when using the addon.
Addons should follow the following conventions:
- Package name should start with `slidev-addon-`. For example, `slidev-addon-name` or `@scope/slidev-addon-name`
- Add `"slidev-addon"` and `"slidev"` in the `keywords` field of your `package.json`
Theme can be used locally without publishing to NPM. If your addon is only for personal use, you can simply use it as a local addon, or publish it as a private scoped package. However, it is recommended to publish it to the NPM registry if you want to share it with others.
================================================
FILE: docs/guide/write-layout.md
================================================
# Writing Layouts
> Please read first.
To create a custom layout, simply create a new Vue file in the `layouts` directory:
```bash
your-slidev/
├── ...
├── slides.md
└── layouts/
├── ...
└── MyLayout.vue
```
Layouts are Vue components, so you can use all the features of Vue in them.
In the layout component, use `` (the default slot) for the slide content:
```vue [default.vue]
```
You can also have [named slots](https://vuejs.org/guide/components/slots.html) for more complex layouts:
```vue [split.vue]
================================================
FILE: packages/client/internals/README.md
================================================
# Internal Components
Components for built-in UIs.
Not exposed to auto-importing. Will need to be imported to use in other components.
================================================
FILE: packages/client/internals/RecordingControls.vue
================================================
================================================
FILE: packages/client/internals/RecordingDialog.vue
================================================
Recording
This will be used in the output filename that might help you better organize your recording chips.
{{
__SLIDEV_HAS_SERVER__
? 'An error occurred on this slide. Check the terminal for more information.'
: 'Failed to fetch this slide. Please check your network connection.'
}}