This guide is for developers integrating Marp Core into an application.
You can configure the behavior of Marp Core by passing constructor options to the Marp class. It allows both Marpit's constructor options and Marp Core-specific options.
import { Marp } from '@marp-team/marp-core'
const marp = new Marp({
html: true,
emoji: {
shortcode: true,
unicode: false,
},
math: 'katex',
minifyCSS: true,
script: {
source: 'cdn',
nonce: 'xxxxxxxxxxxxxxx',
},
slug: false,
// Marpit options are also accepted:
anchor: false,
looseYAML: false,
markdown: {
breaks: false,
},
})Following Marpit options are changed from Marpit's defaults:
cssContainerQuery:false→true(Enable container queries)inlineSVG:false→true(Enable inline SVG slide)looseYAML:false→true(Enable loose YAML front-matter parsing)
markdown: markdown-it options based on CommonMark presetbreaks:false→true(Enable hardbreaks in Markdown)highlight:undefined→ Use Marp Core's syntax highlighter and diagram rendererslinkify:false→true(Enable automatic link detection in Markdown)
Developers can override these defaults and other Marpit options by passing their own values to the Marp constructor.
Controls raw HTML in Markdown. It is similar to markdown-it's html option, but supports an element and attribute allowlist.
- Default: Allow known-safe HTML elements and attributes.
true:⚠️ Allow all raw HTML, including insecure elements and attributes.false: Disallow raw HTML (except structures required by Marpit Markdown).- Object: Use a custom allowlist.
Define allowed elements, and attributes as an array:
const marp = new Marp({
html: {
a: ['href', 'target'],
br: [],
},
})For attributes, you can also define a filter function:
const marp = new Marp({
html: {
img: {
src: (value) => (value.startsWith('https://') ? value : ''),
},
},
})Note
HTML comments and <style> elements required by Marpit directives and style tweaks are parsed regardless of this option.
Pass an object for controlling emoji conversion.
const marp = new Marp({
emoji: {
shortcode: 'twemoji',
unicode: false,
twemoji: {
base: '/resources/twemoji/',
ext: 'svg',
},
},
})Setting for shortcode emoji conversion like :smile::
"twemoji"(default): Convert shortcode emoji to Twemoji image.true: Convert shortcode emoji to Unicode emoji.false: Disable shortcode emoji conversion.
Setting for Unicode emoji conversion like 😄:
"twemoji"(default): Convert Unicode emoji to Twemoji image.true: Unicode emojis are converted into internal tokens, but remain visually unchanged as Unicode.false: Unicode emojis are preserved as is.
Options for Twemoji.
Set base URL as string. Corresponds to twemoji's base option.
By default, Marp Core will use online emoji images through jsDelivr CDN.
The filetype of Twemoji images.
"svg"(default): Use SVG emoji images."png": Use PNG emoji images.
Prerequisite: The corresponding math plugin
@marp-team/marp-core/plugins/mathjaxor@marp-team/marp-core/plugins/katexmust be registered throughuse().
Controls the preferred math library in math typesetting.
true(default): Prefer the first registered math plugin."mathjax": Prefer MathJax first (provided by@marp-team/marp-core/plugins/mathjax)."katex": Prefer KaTeX first (provided by@marp-team/marp-core/plugins/katex).false: Disable math typesetting andmathglobal directive.
Note
- The full build
@marp-team/marp-core/fullregisters MathJax plugin first, and therefore prefers it by default. - When enabled math typesetting,
mathglobal directive in Markdown always takes priority over this setting. - If a preferred math library is not registered, the first available library will be used as fallback.
- The KaTeX plugin has additional configuration options. See KaTeX plugin configuration for details.
Controls CSS minification in the result of render().
true(default): Minify CSS in the result ofrender().false: Do not minify CSS.
Controls the browser helper @marp-team/marp-core/browser script injection.
true(default): Inject the browser helper at the end of slides through<script>.false: Do not inject it; the application must call the browser helper manually.- Object: Inject the browser helper, with additional configuration:
"inline"(default): Embed the inline script in the rendered HTML. It works with offline environments."cdn": Load the script from jsDelivr CDN. It's better if CSP blocks unsafe inline scripts.
You can set a string for nonce attribute to the <script> tag.
const marp = new Marp({
script: {
source: 'cdn',
nonce: 'xxxxxxxxxxxxxxx',
},
})Controls generated id attributes on <h1> through <h6> headings.
true(default): Generate GitHub-like slugs and suffix duplicates.false: Do not generate heading IDs.- Function: Use a custom slugifier function.
- Object: Use custom slugifier and duplicate suffixing.
(text: string) => slug: string
Set a function to generate a slug from heading text.
text: Heading text without Markdown formatting.slug: Generated slug.
(slug: string, index: number) => id: string
Set a function to modify the final ID, from the generated slug and its duplicate index. By default, duplicate slug xxx becomes xxx-1, xxx-2, and so on.
slug: Originally generated slug.index: Zero-based index of the duplicate slug.id: Final ID to be set on the heading.
const marp = new Marp({
slug: {
slugifier: (text) => text.toLowerCase().replaceAll(' ', '_'),
postSlugify: (slug, index) => (index > 0 ? `${slug}_${index}` : slug),
},
})Note
Take care not to confuse Marp Core's slug option and Marpit's anchor option. slug is for the Markdown headings, and anchor is for the slide page elements.
Tip
To fully disable auto-generated id attribute from slides, set both of slug and anchor as false. It's important to avoid breaking your Web application by the collision of same id values in the same document.
Core plugins are optional Marp Core plugins for several features. In some plugins, the developer can configure the behavior of the plugin.
An instance of Marp class has shikiTransformers member, which is an array of Shiki transformers. For more advanced usage, you can push custom transformers to the array to customize the output of syntax highlighting.
import { Marp } from '@marp-team/marp-core'
import shikiPlugin from '@marp-team/marp-core/plugins/shiki'
import { transformerNotationHighlight } from '@shikijs/transformers'
const marp = new Marp().use(shikiPlugin())
marp.shikiTransformers.push(transformerNotationHighlight())In this instance, transformerNotationHighlight() from @shikijs/transformers allows line highlighting through Shiki's specific notation:
```ts
const marp = new Marp().use(shikiPlugin())
marp.shikiTransformers.push(transformerNotationHighlight()) // [!code highlight]
```It means the same as:
```ts {2}
const marp = new Marp().use(shikiPlugin())
marp.shikiTransformers.push(transformerNotationHighlight())
```katexPlugin() accepts custom options and a font path:
import { Marp } from '@marp-team/marp-core'
import katexPlugin from '@marp-team/marp-core/plugins/katex'
const marp = new Marp().use(
katexPlugin({
options: { leqno: true, fleqn: true },
fontPath: '/assets/katex-fonts/',
}),
)Custom options for KaTeX. Please refer to KaTeX's options for details.
Set a path to KaTeX font files. It is used in the @font-face rule of the KaTeX CSS.
- Default: Use KaTeX fonts through jsDelivr CDN.
- String: Use a custom path to KaTeX font files, like
url({fontPath}KaTeX_*.woff2). false: Use original path in the KaTeX CSS, likeurl(fonts/KaTeX_*.woff2).
Note
- You cannot pass options to the KaTeX plugin registered by a full build
@marp-team/marp-core/full. katexOptionandkatexFontPathoptions in themathoption of theMarpconstructor, which were available up to v4, have been deprecated in favor of the plugin configuration.
The browser helper is exported separately from @marp-team/marp-core/browser. It's required for following purposes:
- Polyfill: Apply
@marp-team/marpit-svg-polyfillto support correct rendering of inline SVG slides for Safari. - Auto-scaling: The browser helper replaces elements marked as scalable by auto-scaling features into the custom element provided by Marp Core.
By default, Marp Core injects the browser helper script at the end of slides through a <script> tag. However, this injection may be blocked or even prohibited for security reasons.
If so, you can disable the script injection by setting the script option of the Marp constructor as false. In this case, you must call the browser helper manually after rendering slides in the browser.
// Server-side conversion
import { Marp } from '@marp-team/marp-core'
const marp = new Marp({ script: false })
const rendered = marp.render('# <!-- fit --> Hello!')// Browser-side rendering and script execution
import { browser } from '@marp-team/marp-core/browser'
document.body.innerHTML = `<style>${rendered.css}</style>${rendered.html}`
browser()browser() observes the whole document by default. If you want to limit the observation target, you can pass a specific element as an argument.
const element = document.getElementById('marp-slide-container')
browser(element)The most helpful use cases are <iframe> and shadow DOM. Both approaches can isolate the rendered slides and styles from the parent document, but browser() cannot observe inside them. Thus, you must pass the inner element to browser().
const iframeElm = document.querySelector('iframe#marp-iframe-elm')
iframeElm.contentDocument.body.innerHTML = `<style>${rendered.css}</style>${rendered.html}`
browser(iframeElm.contentDocument.body)Usage in Shadow DOM
// Shadow DOM
const shadowElm = document.getElementById('marp-shadow-elm')
const shadowRoot = shadowElm.attachShadow({ mode: 'open' })
shadowRoot.innerHTML = `<style>${rendered.css}</style>${rendered.html}`
browser(shadowRoot)Shadow DOM looks like an ideal way to isolate Marp rendering from the document, but actually Chromium cannot load and apply Web Fonts within a Shadow DOM, which can result in incorrect rendering (https://crbug.com/41085401).
browser() returns a cleanup function with update() and cleanup() methods.
element.innerHTML = renderSlide()
const browserHelper = browser(element)
// Call update() after replacing the rendered DOM under the same target
element.innerHTML = renderAnotherSlide()
browserHelper.update()
// Call cleanup() when the target is no longer used
browserHelper.cleanup() // browserHelper() is also equivalent to thisIt's helpful for building a Marp component that re-renders the slides in the same element.
React/Next.js example
// next.config.mjs
export default {
serverExternalPackages: ['@marp-team/marp-core'],
}import 'server-only'
import { Marp } from '@marp-team/marp-core/full'
import { MarpSlideClient } from './MarpSlideClient'
const marp = new Marp({
script: false,
container: false, // Disable CSS scoping to Marpit container element
})
export const MarpSlide = ({ markdown, page = 1 }) => {
const rendered = marp.render(markdown, { htmlAsArray: true })
const renderPage = Math.min(Math.max(page - 1, 0), rendered.html.length - 1)
return <MarpSlideClient html={rendered.html[renderPage]} css={rendered.css} />
}'use client'
import { useEffect, useRef } from 'react'
import { browser } from '@marp-team/marp-core/browser'
export const MarpSlideClient = ({ html, css }) => {
const ref = useRef(null)
useEffect(() => {
if (!ref.current) return
ref.current.contentDocument.head.innerHTML = '<base target="_parent"/>'
const root = ref.current.contentDocument.body
root.style.margin = '0'
root.innerHTML = `<style>${css}</style>${html}`
const browserHelper = browser(root)
return () => browserHelper.cleanup()
}, [html, css])
return <iframe ref={ref} title="Marp Slide" />
}