markdown-it
Use Lumis directly in markdown-it with markdown-it-lumis.
Use @lumis-sh/markdown-it-lumis when your renderer is built on markdown-it.
Install
npm install markdown-it @lumis-sh/markdown-it-lumis @lumis-sh/themes
Example
import MarkdownIt from 'markdown-it'
import markdownItLumis from '@lumis-sh/markdown-it-lumis'
import {htmlInline} from '@lumis-sh/lumis/formatters'
import javascript from '@lumis-sh/lumis/langs/javascript'
import rust from '@lumis-sh/lumis/langs/rust'
import plaintext from '@lumis-sh/lumis/langs/plaintext'
import latte from '@lumis-sh/themes/catppuccin_latte'
const md = new MarkdownIt()
const lumis = await markdownItLumis({
formatter: (language) => htmlInline({language, theme: latte}),
languages: [javascript, rust, plaintext],
})
lumis(md)
const html = md.render(markdown)
Use this for tools like VitePress or for custom markdown-it renderers.
Exports
default
const lumis = await markdownItLumis(options)
lumis(md)
Creates a Lumis highlighter and returns an installer function for a markdown-it instance.
fromHighlighter
import {createHighlighter} from '@lumis-sh/lumis'
import {fromHighlighter} from '@lumis-sh/markdown-it-lumis'
import {htmlInline} from '@lumis-sh/lumis/formatters'
import {bundledLanguages} from '@lumis-sh/lumis/bundles/web'
const highlighter = await createHighlighter({languages: [bundledLanguages]})
await highlighter.loadLanguage(bundledLanguages.javascript)
const lumis = fromHighlighter(highlighter, options)
lumis(md)
Use this when you want to reuse an existing highlighter.
Options
formatter- required callback that receives the fence language and returns a Lumis formatterlanguages- languages to register or load during setup before calling syncmd.render(); acceptsLanguageobjects, bundles, and string refs when a bundle is also presentfenceAttrsOnPre- put a fence's attributes on<pre>rather than<code>. Defaults totrue
Behavior
- overrides fenced code rendering
- keeps the attributes a fence carries, which most highlighter plugins drop
- loads any language refs passed in
languagesduring async setup - renders synchronously after setup, so load the languages you expect to use
- falls back to the default fence renderer if highlighting fails and no fallback succeeds
Fence attributes
markdown-it-attrs and @mdit/plugin-attrs let a fence carry attributes:
```js {#example .code-card data-panel="install"}
const x = 1
```
Those survive here, on the <pre>:
<pre class="lumis code-card" style="color: #f8f8f2; background-color: #282a36;" id="example" data-panel="install"><code class="language-javascript" translate="no" tabindex="0">…
class unions with the classes Lumis generates, style is appended after the theme's declarations, and everything else replaces what Lumis would have written, translate and tabindex included. It is the same merge the formatters' own preAttrs and codeAttrs go through, because that is what the plugin hands them to.
<pre> is the placement markdown-it-attrs 5 documents, under this same fenceAttrsOnPre name. markdown-it's own fence renderer puts them on <code> instead; pass fenceAttrsOnPre: false for that.
markdownItLumis({
formatter: (language) => htmlInline({language, theme: latte}),
fenceAttrsOnPre: false,
})
Two things about markdown-it-attrs itself, neither of them Lumis':
- Its
<pre>placement only takes effect when it recognises markdown-it's defaultfencerule by reference, which it looks up through its ownrequire('markdown-it'). Load markdown-it as ESM and that is a different module instance, so the check reads "custom renderer", the wrapper stands down, and the attributes land on<code>. Lumis installs afencerenderer of its own, so the wrapper stands down for it either way and the placement above is Lumis' rather than inherited. - It reads
{...}after the language, which is also where several highlighters read their own metadata. Give it aleftDelimiter/rightDelimiterof its own if you hit that.
Most highlighter plugins drop these attributes rather than place them. @shikijs/markdown-it loses them outright, because it hooks options.highlight and returns a full <pre> block, and markdown-it's default fence renderer returns early on exactly that, never reaching the branch that renders a token's attributes.