# Marpit
Marpit is a lightweight framework for creating slide decks from Markdown. It transforms Markdown content and CSS themes into static HTML and CSS that can be used as a logicless slide deck or converted to PDF by printing in a browser. The framework is designed to output minimal assets while providing powerful features like directives for slide configuration, image syntax extensions for backgrounds, and a clean CSS theming system.
Marpit serves as the foundational converter in the Marp ecosystem and is built on markdown-it for parsing. It extends standard Markdown with directives (YAML-based configuration), slide backgrounds via image syntax, header/footer support, pagination, and inline SVG rendering for pixel-perfect scaling. The theming system allows pure CSS styling without predefined classes or mixins, making it straightforward for developers to create custom presentation themes.
## Marpit Class Constructor
The main entry point for creating slide decks. Instantiate with options to configure Markdown parsing behavior, container elements, inline SVG mode, heading dividers, and more.
```javascript
import { Marpit, Element } from '@marp-team/marpit'
// Basic instance with default settings
const marpit = new Marpit()
// Full configuration with all options
const customMarpit = new Marpit({
// Enable HTML tags and line breaks in Markdown
markdown: {
html: true,
breaks: true,
},
// Custom container elements for HTML output
container: [
new Element('article', { id: 'presentation' }),
new Element('div', { class: 'slides' }),
],
// Wrap each slide in custom element
slideContainer: new Element('div', { class: 'slide' }),
// Enable experimental inline SVG mode for pixel-perfect scaling
inlineSVG: true,
// Auto-divide slides at heading level 2 or higher
headingDivider: 2,
// Enable CSS container query support
cssContainerQuery: true,
// Enable CSS nesting support
cssNesting: true,
// Make output printable to PDF
printable: true,
// Set default language attribute for slides
lang: 'en',
// Enable loose YAML parsing for directives
looseYAML: false,
// Custom anchor callback for slide IDs
anchor: (index) => `slide-${index + 1}`,
})
```
## Marpit.render() Method
Renders Markdown content into HTML and CSS. Returns an object containing the rendered HTML string, CSS styles, and collected HTML comments (useful for presenter notes).
```javascript
import { Marpit } from '@marp-team/marpit'
const marpit = new Marpit()
// Add a theme first
marpit.themeSet.default = marpit.themeSet.add(`
/* @theme presentation */
section {
width: 1280px;
height: 720px;
font-size: 32px;
padding: 40px;
background: #1a1a2e;
color: #eee;
}
h1 { color: #00d4ff; }
`)
const markdown = `
---
paginate: true
header: 'My Presentation'
---
# Welcome to Marpit
This is the first slide with pagination enabled.
---
## Second Slide
- Bullet point 1
- Bullet point 2
---
## Third Slide
Final slide content here.
`
// Render to HTML and CSS
const { html, css, comments } = marpit.render(markdown)
// html: '
...
'
// css: 'div.marpit { ... } section { ... }'
// comments: [['This comment becomes a presenter note'], ['Another presenter note...'], []]
// Create complete HTML document
const document = `
${html}
`
```
## Render HTML as Array
Output HTML as an array of strings, one per slide page. Useful for custom slide navigation or individual slide manipulation in applications.
```javascript
import { Marpit } from '@marp-team/marpit'
const marpit = new Marpit()
const markdown = `
# Page 1
First slide content
---
# Page 2
Second slide content
---
# Page 3
Third slide content
`
// Pass htmlAsArray option to get array output
const { html, css, comments } = marpit.render(markdown, { htmlAsArray: true })
// html is now an array:
// [
// '\nPage 1
\nFirst slide content
\n\n',
// '\nPage 2
\nSecond slide content
\n\n',
// '\nPage 3
\nThird slide content
\n\n'
// ]
// Use slides individually (still need container for CSS scoping)
html.forEach((slideHtml, index) => {
console.log(`Slide ${index + 1}:`, slideHtml)
})
```
## ThemeSet.add() Method
Adds a theme CSS string to the theme set. The CSS must include a `@theme` meta comment to specify the theme name. Returns a Theme instance.
```javascript
import { Marpit } from '@marp-team/marpit'
const marpit = new Marpit()
// Add a complete theme with all styling
const theme = marpit.themeSet.add(`
/* @theme corporate */
section {
width: 1280px;
height: 720px;
font-size: 28px;
padding: 40px;
background-color: #ffffff;
color: #333333;
}
/* Style headings */
h1 {
font-size: 48px;
color: #0066cc;
border-bottom: 2px solid #0066cc;
}
h2 {
font-size: 36px;
color: #004499;
}
/* Pagination styling */
section::after {
content: 'Page ' attr(data-marpit-pagination) ' / ' attr(data-marpit-pagination-total);
position: absolute;
right: 40px;
bottom: 30px;
font-size: 16px;
color: #666;
}
/* Header and footer positioning */
header, footer {
position: absolute;
left: 40px;
right: 40px;
height: 30px;
font-size: 14px;
color: #888;
}
header { top: 20px; }
footer { bottom: 20px; }
/* Lead slide class for title pages */
section.lead {
display: flex;
flex-direction: column;
justify-content: center;
text-align: center;
background: linear-gradient(135deg, #0066cc, #004499);
color: white;
}
section.lead h1 {
color: white;
border: none;
}
`)
// Set as default theme
marpit.themeSet.default = theme
// Now use the theme
const { html, css } = marpit.render(`
# Corporate Presentation
---
## Agenda
- Topic 1
- Topic 2
`)
```
## Theme Importing with @import
Create customized themes based on existing themes using CSS @import or @import-theme rules.
```javascript
import { Marpit } from '@marp-team/marpit'
const marpit = new Marpit()
// Add base theme first
marpit.themeSet.add(`
/* @theme base */
section {
width: 1280px;
height: 720px;
font-size: 30px;
padding: 40px;
background: #fff;
color: #333;
}
h1 { color: #333; font-size: 48px; }
h2 { color: #555; font-size: 36px; }
code { background: #f4f4f4; padding: 2px 8px; }
`)
// Create dark theme that imports base
marpit.themeSet.add(`
/* @theme dark */
@import 'base';
section {
background: #1a1a2e;
color: #eee;
}
h1 { color: #00d4ff; }
h2 { color: #7dd3fc; }
code { background: #2d2d44; color: #f8f8f2; }
`)
// Create colorful theme variant
marpit.themeSet.add(`
/* @theme colorful */
@import 'base';
section {
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
color: white;
}
h1, h2 { color: white; }
`)
// Use themes via directive
const { css } = marpit.render(`
# Dark Theme Slide
`)
```
## ThemeSet Management Methods
Methods for managing themes in the theme set: get, has, delete, clear, and iterate through themes.
```javascript
import { Marpit } from '@marp-team/marpit'
const marpit = new Marpit()
// Add multiple themes
marpit.themeSet.add('/* @theme light */ section { background: #fff; }')
marpit.themeSet.add('/* @theme dark */ section { background: #222; }')
marpit.themeSet.add('/* @theme blue */ section { background: #1e40af; }')
// Check number of themes
console.log(marpit.themeSet.size) // 3
// Check if theme exists
console.log(marpit.themeSet.has('dark')) // true
console.log(marpit.themeSet.has('unknown')) // false
// Get theme instance
const darkTheme = marpit.themeSet.get('dark')
console.log(darkTheme.name) // 'dark'
console.log(darkTheme.css) // '/* @theme dark */ section { background: #222; }'
// Get theme with fallback to default/scaffold
const theme = marpit.themeSet.get('nonexistent', true) // Returns default or scaffold
// Get theme metadata
const meta = marpit.themeSet.getThemeMeta('dark', 'theme') // 'dark'
// Get theme property (e.g., width, height)
const width = marpit.themeSet.getThemeProp('light', 'width')
// Iterate through all themes
for (const theme of marpit.themeSet.themes()) {
console.log(`Theme: ${theme.name}`)
}
// Delete a specific theme
marpit.themeSet.delete('blue')
console.log(marpit.themeSet.size) // 2
// Clear all themes
marpit.themeSet.clear()
console.log(marpit.themeSet.size) // 0
```
## Custom Directives
Define custom global and local directives to extend Marpit's functionality. Global directives apply to the entire deck, local directives apply per-slide.
```javascript
import { Marpit } from '@marp-team/marpit'
const marpit = new Marpit()
// Custom global directive for presentation metadata
marpit.customDirectives.global.author = (value, marpit) => {
return { author: value }
}
marpit.customDirectives.global.date = (value, marpit) => {
return { date: value }
}
// Custom local directive for color presets
marpit.customDirectives.local.colorPreset = (value, marpit) => {
const presets = {
ocean: { backgroundColor: '#0077b6', color: '#caf0f8' },
sunset: { backgroundColor: '#e63946', color: '#f1faee' },
forest: { backgroundColor: '#2d6a4f', color: '#d8f3dc' },
midnight: { backgroundColor: '#1d3557', color: '#a8dadc' },
}
return presets[value] || {}
}
// Custom local directive for text alignment
marpit.customDirectives.local.align = (value, marpit) => {
// Returns class to be applied to section
const alignments = {
center: 'text-center',
right: 'text-right',
left: 'text-left',
}
return alignments[value] ? { class: alignments[value] } : {}
}
// Add theme with preset support
marpit.themeSet.default = marpit.themeSet.add(`
/* @theme custom */
section { width: 1280px; height: 720px; padding: 40px; }
section.text-center { text-align: center; }
section.text-right { text-align: right; }
`)
// Use custom directives in Markdown
const { html, css } = marpit.render(`
---
author: John Doe
date: 2024-01-15
---
# Ocean Theme Slide
Centered text with ocean colors
---
# Sunset Slide
This slide uses sunset colors (spot directive with underscore)
---
# Back to Ocean
Previous colorPreset continues
`)
```
## Marpit.use() Method
Extend Marpit with markdown-it plugins, PostCSS plugins, or Marpit-specific plugins. Returns the Marpit instance for chaining.
```javascript
import { Marpit } from '@marp-team/marpit'
import markdownItEmoji from 'markdown-it-emoji'
import markdownItContainer from 'markdown-it-container'
const marpit = new Marpit()
// Chain multiple plugins
marpit
// Add emoji support
.use(markdownItEmoji)
// Add custom containers for multi-column layouts
.use(markdownItContainer, 'columns', {
render: (tokens, idx) => {
if (tokens[idx].nesting === 1) {
return '\n'
}
return '
\n'
},
})
.use(markdownItContainer, 'column', {
render: (tokens, idx) => {
if (tokens[idx].nesting === 1) {
return '\n'
}
return '
\n'
},
})
// Add theme with column support
marpit.themeSet.default = marpit.themeSet.add(`
/* @theme with-columns */
section {
width: 1280px;
height: 720px;
padding: 40px;
}
.columns {
display: flex;
gap: 20px;
}
.column {
flex: 1;
}
`)
// Use plugins in Markdown
const { html, css } = marpit.render(`
# Emojis Work! :rocket: :tada:
---
# Multi-Column Layout
::: columns
::: column
## Left Column
- Point 1
- Point 2
:::
::: column
## Right Column
- Point A
- Point B
:::
:::
`)
```
## Marpit Plugin Factory
Create Marpit-specific plugins that have access to the Marpit instance via `md.marpit`. Use the plugin factory from `@marp-team/marpit/plugin`.
```javascript
import { Marpit } from '@marp-team/marpit'
import { marpitPlugin } from '@marp-team/marpit/plugin'
// Create a Marpit plugin with access to Marpit instance
const slideCounterPlugin = marpitPlugin((md) => {
const { marpit } = md
// Add custom directive
marpit.customDirectives.global.showSlideCount = (value) => {
return { showSlideCount: value === 'true' || value === true }
}
// Extend renderer
const originalRender = md.renderer.render.bind(md.renderer)
md.renderer.render = (tokens, options, env) => {
const result = originalRender(tokens, options, env)
// Custom processing with access to marpit
return result
}
})
// Plugin that adds a built-in theme
const builtInThemePlugin = marpitPlugin((md) => {
const { marpit } = md
marpit.themeSet.add(`
/* @theme plugin-theme */
section {
width: 1280px;
height: 720px;
background: #2d3436;
color: #dfe6e9;
font-family: system-ui, sans-serif;
}
h1 { color: #74b9ff; }
`)
})
// Use plugins
const marpit = new Marpit()
.use(slideCounterPlugin)
.use(builtInThemePlugin)
const { html, css } = marpit.render(`
# Plugin-Provided Theme
`)
```
## Element Class for Container Customization
Create custom HTML container elements for wrapping the slide deck or individual slides with specific attributes.
```javascript
import { Marpit, Element } from '@marp-team/marpit'
// Create instance with custom containers
const marpit = new Marpit({
// Outer containers wrapping entire deck
container: [
new Element('main', { id: 'app', role: 'main' }),
new Element('div', { class: 'presentation-wrapper' }),
],
// Container for each individual slide
slideContainer: new Element('article', { class: 'slide-page' }),
})
marpit.themeSet.default = marpit.themeSet.add(`
/* @theme custom-container */
section { width: 1280px; height: 720px; padding: 40px; }
`)
const { html, css } = marpit.render(`
# Slide 1
---
# Slide 2
`)
// Output structure:
//
//
//
// Disable containers entirely
const noContainerMarpit = new Marpit({
container: false,
})
```
## Directives in Markdown
Use YAML-based directives in HTML comments or front-matter to configure slides. Global directives affect all slides, local directives affect current and following slides, spot directives (underscore prefix) affect only current slide.
```markdown
---
theme: default
paginate: true
header: 'Company Name'
footer: '© 2024'
headingDivider: 2
---
# Main Presentation Title
Subtitle goes here
---
## First Section
Regular content with light background
---
## Still Light Background
Local directives persist across slides
---
## Dark Slide (Spot Directive)
Only this slide is dark (underscore prefix)
---
## Back to Light
The spot directive only affected the previous slide
---
## Appendix
This slide shows page number but doesn't increment counter
---
## Hidden from Count
This slide is hidden from pagination entirely
```
## Image Syntax Extensions
Extended Markdown image syntax for backgrounds, resizing, and filters. Use keywords in the alt text to control image behavior.
```markdown
# Inline Image Resizing



---
# Image Filters




---
# Slide Background

Content appears over the background
---
# Background Size Options

Use 'cover' (default), 'contain', 'fit', 'auto', or percentage
---
# Background with Color

Solid color background using hex
---
# Multiple Backgrounds



Images arrange horizontally
---
# Vertical Multiple Backgrounds



---
# Split Background Left

Content on the right side
---
# Split Background Right with Size

Content takes 60% on the left
```
## Complete Application Example
A full example showing Marpit used to build a presentation generator with themes, plugins, and custom features.
```javascript
import { Marpit, Element } from '@marp-team/marpit'
import { marpitPlugin } from '@marp-team/marpit/plugin'
import fs from 'fs'
// Custom plugin for auto-generated table of contents
const tocPlugin = marpitPlugin((md) => {
md.marpit.customDirectives.global.toc = (value) => {
return { generateToc: value === 'true' }
}
})
// Initialize Marpit with full configuration
const marpit = new Marpit({
markdown: { html: true, breaks: true },
inlineSVG: true, // Enable advanced backgrounds
headingDivider: false,
cssContainerQuery: true,
})
.use(tocPlugin)
// Add comprehensive theme
marpit.themeSet.default = marpit.themeSet.add(`
/* @theme professional */
:root {
--primary: #2563eb;
--secondary: #1e40af;
--background: #ffffff;
--text: #1f2937;
--muted: #6b7280;
}
section {
width: 1280px;
height: 720px;
padding: 60px;
background: var(--background);
color: var(--text);
font-family: 'Inter', system-ui, sans-serif;
font-size: 28px;
line-height: 1.6;
}
h1 {
font-size: 56px;
color: var(--primary);
margin-bottom: 20px;
}
h2 {
font-size: 42px;
color: var(--secondary);
}
code {
background: #f3f4f6;
padding: 4px 8px;
border-radius: 4px;
font-size: 0.9em;
}
pre {
background: #1f2937;
color: #f9fafb;
padding: 20px;
border-radius: 8px;
overflow-x: auto;
}
pre code {
background: none;
padding: 0;
}
section::after {
content: attr(data-marpit-pagination) ' / ' attr(data-marpit-pagination-total);
position: absolute;
right: 60px;
bottom: 40px;
font-size: 16px;
color: var(--muted);
}
header {
position: absolute;
top: 30px;
left: 60px;
right: 60px;
font-size: 14px;
color: var(--muted);
}
footer {
position: absolute;
bottom: 30px;
left: 60px;
font-size: 14px;
color: var(--muted);
}
/* Title slide variant */
section.title {
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
text-align: center;
background: linear-gradient(135deg, var(--primary), var(--secondary));
color: white;
}
section.title h1 {
color: white;
font-size: 64px;
}
section.title p {
font-size: 24px;
opacity: 0.9;
}
/* Two column layout */
section.columns {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 40px;
}
`)
// Sample presentation content
const presentation = `
---
paginate: true
header: 'Technical Workshop'
footer: 'Confidential'
---
# Building Modern Applications
A comprehensive guide to software architecture
*Workshop 2024*
---
## Agenda
1. Introduction to Architecture Patterns
2. Hands-on Implementation
3. Best Practices & Code Review
4. Q&A Session
---
## Key Concepts
### Design Patterns
- Singleton
- Factory
- Observer
- Strategy
### Architecture Styles
- Microservices
- Event-Driven
- Serverless
- Monolithic
---
## Code Example
\`\`\`javascript
class UserService {
constructor(repository) {
this.repository = repository;
}
async createUser(data) {
const user = new User(data);
return this.repository.save(user);
}
}
\`\`\`
---

## Visual Architecture
The diagram shows our system components:
- **API Gateway**: Entry point
- **Services**: Business logic
- **Database**: Data persistence
---
## Questions?
Contact: team@example.com
`
// Render presentation
const { html, css, comments } = marpit.render(presentation)
// Generate complete HTML file
const htmlDocument = `
Technical Workshop
${html}
`
// Write to file
fs.writeFileSync('presentation.html', htmlDocument)
// Export presenter notes
const notes = comments
.map((slideNotes, i) => `Slide ${i + 1}:\n${slideNotes.join('\n')}`)
.filter((n) => n.includes('\n'))
.join('\n\n')
fs.writeFileSync('presenter-notes.txt', notes)
console.log('Presentation generated successfully!')
```
## Summary
Marpit is ideal for developers building presentation tools, documentation systems, or any application requiring Markdown-to-slides conversion. The framework excels in scenarios where minimal output size matters, such as embedding presentations in web applications, generating printable PDFs, or creating slide-based content management systems. Its markdown-it foundation ensures compatibility with the broader Markdown ecosystem while the PostCSS-based theming allows sophisticated CSS processing.
Integration patterns typically involve creating a Marpit instance, registering custom themes via `themeSet.add()`, optionally extending functionality with plugins via `use()`, and rendering Markdown with `render()`. For applications requiring fine-grained control, custom directives provide a powerful extension mechanism, while the `htmlAsArray` option enables per-slide manipulation. The framework's pure HTML/CSS output makes it framework-agnostic, working seamlessly with React, Vue, vanilla JavaScript, or server-side rendering environments.