Valkyrian Labs logo

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 to false to return the incoming Payload config unchanged
  • collections: map of collection slugs to true, an options object, or a falsey value to skip
  • code: Shiki and fenced code rendering defaults
  • icons: local SVG icon packs available to Markdown directives
  • palettes: named colour palettes for icons and directives (see Palettes)
  • appearance: true adds the Markdown Appearance global, where editors and MCP agents manage palettes at runtime (see Palettes)
  • themes: directive theme registry extensions
  • config: 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:

  1. the settings you pass: the settings object, a Payload config, or a Payload instance;
  2. otherwise the registry, which holds the settings of the most recently built config;
  3. 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 to content
  • field: field options passed to markdownField() except name
  • installField: explicitly add or skip a standalone Markdown field
  • installIntoBlocks: explicitly add or skip MarkdownBlock inside collection blocks fields
  • code: collection-scoped code rendering overrides
  • themes: collection-scoped directive themes
  • palettes: collection-scoped colour palettes
  • config: collection-scoped wrapper and typography config

Field Options

Auto-installed fields support:

  • admin
  • defaultValue
  • label
  • localized
  • required
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.langs to code.langs
  • config.options.lineNumbers to code.lineNumbers
  • config.options.theme to code.shikiTheme
  • config.options.enhancedCodeBlocks to code.enhanced
  • config.fullBleedCode to code.fullBleed
  • config.sectionClassName to directive themes
  • config.columnClassName to directive themes

New code values win over legacy aliases at the same scope.