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/lumis @lumis-sh/themes \
@lumis-sh/wasm-javascript @lumis-sh/wasm-rust @lumis-sh/wasm-bundle-webExample
import MarkdownIt from 'markdown-it'
import markdownItLumis from '@lumis-sh/markdown-it-lumis'
import {htmlInline} from '@lumis-sh/lumis/formatters'
import plaintext from '@lumis-sh/lumis/langs/plaintext'
import javascript from '@lumis-sh/wasm-javascript'
import rust from '@lumis-sh/wasm-rust'
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 web from '@lumis-sh/wasm-bundle-web'
const highlighter = await createHighlighter({
languages: [web],
})
await highlighter.loadLanguage(web.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 totrueinlineCode- also highlight inline code that names its language; defaults tofalse. See Inline code.
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
Inline code
With inlineCode: true, a code span is highlighted when it names its language
with a {:lang} suffix. Code spans that name none keep markdown-it's own
rendering, so prose in backticks is never recolored:
Declare it with `const answer = 42{:javascript}`.With markdown-it-attrs, a language-* class or data-language attribute
works too, and the span's other attributes are kept:
Declare it with `const answer = 42`{.language-javascript #answer}.The suffix is removed and the code is written with the
inline structure. The formatter's theme colors go on
the <code> with the lumis class:
<code class="lumis" style="color: #4c4f69; background-color: #eff1f5;"><span style="color: #8839ef;">const</span> …</code>Load the languages inline code names in languages, as for fences. A language
that is not loaded renders as plain text. nohighlight and no-highlight skip
a span, and a formatter that is not one of the built-in HTML formatters leaves
inline code to markdown-it.
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.