Plugin Config
Use the public Payload Markdown config model for fields, blocks, code rendering, themes, and presentation defaults.
Plugin Config
Full Example
1import { DEFAULT_CODE_LANGS, payloadMarkdown } from 'payload-markdown'2 3payloadMarkdown({4 enabled: true,5 code: {6 enhanced: true,7 fullBleed: false,8 langs: [...DEFAULT_CODE_LANGS, 'latex', 'r'],9 lineNumbers: true,10 shikiTheme: 'github-dark',11 },12 icons: {13 baseDir: '../public/icons',14 packs: [15 { alias: 'fa-duotone', path: 'fa/duotone' },16 { alias: 'brand', path: 'brand' },17 ],18 },19 collections: {20 pages: true,21 posts: {22 fieldName: 'body',23 field: {24 label: 'Body Markdown',25 localized: true,26 required: true,27 },28 installField: true,29 installIntoBlocks: false,30 code: {31 lineNumbers: false,32 },33 config: {34 variant: 'docs',35 },36 themes: {37 card: {38 items: [39 {40 name: 'postHeroCard',41 classes: 'rounded-2xl border border-white/10 bg-cyan-950/30 p-5',42 },43 ],44 },45 },46 },47 },48 config: {49 size: 'lg',50 variant: 'blog',51 },52 themes: {53 card: {54 items: [55 {56 name: 'feature',57 classes: 'rounded-2xl border border-cyan-400/40 bg-cyan-950/30 p-5',58 },59 ],60 },61 },62})
Top-Level Options
enabled: defaults to enabled behavior; set tofalseto return the incoming Payload config unchangedcollections: map of collection slugs totrue, an options object, or a falsey value to skipcode: Shiki and fenced code rendering defaultsicons: local SVG icon packs available to Markdown directivespalettes: named colour palettes for icons and directives (see Palettes)appearance:trueadds the Markdown Appearance global, where editors and MCP agents manage palettes at runtime (see Palettes)themes: directive theme registry extensionsconfig: Markdown wrapper and typography defaults
Runtime settings initialization
Runtime helpers read plugin settings from payloadMarkdown(...). If you use renderer helpers before the plugin initializes, getPayloadMarkdownSettings() throws. In normal Payload usage, include the plugin in the config before rendering Markdown.
Where Settings Live
payloadMarkdown(...) resolves its render settings (code, config, icons, themes and each collection's code, config and themes) into a frozen, serialisable object and stores it in two places:
- on the Payload config it returns, as
config.custom.payloadMarkdown(server-only); - in a process-wide registry that every installed copy of the plugin shares (under either package name), so a second copy (for example one installed by another plugin) renders with the same settings.
MarkdownRenderer, MarkdownBlockComponent and renderMarkdown use, in order:
- the
settingsyou pass: the settings object, a Payload config, or a Payload instance; - otherwise the registry, which holds the settings of the most recently built config;
- otherwise no plugin defaults.
1<MarkdownRenderer markdown={doc.content} settings={payload} />
If one process builds several Payload configs with different Markdown settings (for example multi-tenant setups), pass settings explicitly; without it, every renderer uses the last built config. enabled: false clears the registry.
When copies with different versions are loaded, the plugin logs one console.warn naming the versions. Install a single version to keep rendering consistent.
Icons
Configure local SVG icon packs with icons:
1payloadMarkdown({2 icons: {3 baseDir: '../public/icons',4 packs: [5 { alias: 'fa-duotone', path: 'fa/duotone' },6 { alias: 'brand', path: 'brand' },7 ],8 },9})
Expected folder layout:
1public/icons/2 fa/duotone/3 home.svg4 rocket.svg5 brand/6 github.svg
Markdown references use @pack/name:
1::button[Home]{2 href="/home"3 icon="@fa-duotone/home"4}5 6::button[GitHub]{7 href="https://github.com/valkyrianlabs"8 icon="@brand/github"9 newTab=true10}
Only local SVG packs are supported. The plugin does not integrate FortAwesome packages, fetch remote icons, or accept arbitrary icon URLs.
Paid or pro icon files should stay local and gitignored. CI-safe tests and fixtures should use tiny committed SVG fixtures outside public/icons, and local paid-icon checks should be opt-in only.
The server renderer emits sanitized inline SVG in the rendered HTML. Icon files are parsed with an HTML parser and filtered through a strict SVG allowlist: only the first top-level <svg> is kept; <script>, <style>, <foreignObject>, animation elements, images, event-handler attributes, and non-#fragment hrefs are removed. Icons that rely on an embedded <style> block (for example duotone class rules) should express those styles as SVG presentation attributes or in your site CSS. If your app needs a bundler-backed static import registry for SVG component workflows, use the advanced icon registry helper to generate static imports from your local pack layout. Those imports rely on your host app's SVG support, such as Next, SVGR, Webpack, Turbopack, or an equivalent loader. Keep generated files that import paid icons out of source control.
Collection Options
Collection entries can be true or an object:
1payloadMarkdown({2 collections: {3 posts: true,4 pages: {5 fieldName: 'content',6 installField: false,7 installIntoBlocks: true,8 },9 },10})
Collection object options:
fieldName: name for the auto-installed Markdown field, defaulting tocontentfield: field options passed tomarkdownField()exceptnameinstallField: explicitly add or skip a standalone Markdown fieldinstallIntoBlocks: explicitly add or skipMarkdownBlockinside collectionblocksfieldscode: collection-scoped code rendering overridesthemes: collection-scoped directive themespalettes: collection-scoped colour palettesconfig: collection-scoped wrapper and typography config
Field Options
Auto-installed fields support:
admindefaultValuelabellocalizedrequired
1payloadMarkdown({2 collections: {3 posts: {4 fieldName: 'body',5 field: {6 admin: {7 description: 'Use Markdown and supported directives.',8 },9 defaultValue: '# Draft',10 label: 'Body Markdown',11 localized: true,12 required: true,13 },14 installField: true,15 },16 },17})
Config Namespace
config controls presentation around the rendered Markdown:
1payloadMarkdown({2 config: {3 className: '[&_li::marker]:text-cyan-200/90',4 colorScheme: 'auto',5 enableGutter: true,6 mutedHeadings: true,7 size: 'lg',8 variant: 'blog',9 wrapperClassName: 'max-w-4xl',10 },11})
Supported variants are blog, docs, compact, and unstyled. Supported sizes are lg, md, and sm. colorScheme is auto (default), light, or dark; see Light And Dark.
Split Field And Block Config
config can also be split by scope:
1payloadMarkdown({2 config: {3 blocks: {4 size: 'md',5 variant: 'docs',6 },7 field: {8 size: 'lg',9 variant: 'blog',10 },11 },12})
Use the split shape when block layouts need denser typography while standalone fields use article-style typography.
Deprecated Aliases
These remain supported but are not preferred:
config.options.langstocode.langsconfig.options.lineNumberstocode.lineNumbersconfig.options.themetocode.shikiThemeconfig.options.enhancedCodeBlockstocode.enhancedconfig.fullBleedCodetocode.fullBleedconfig.sectionClassNameto directive themesconfig.columnClassNameto directive themes
New code values win over legacy aliases at the same scope.