LumisDocs
Integrations

rehype-lumis

Use Lumis directly in rehype and unified pipelines with rehype-lumis.

Full example on GitHub

Use @lumis-sh/rehype-lumis when your stack already has a rehype stage.

Install

npm install @lumis-sh/rehype-lumis @lumis-sh/lumis @lumis-sh/themes \
  @lumis-sh/wasm-javascript @lumis-sh/wasm-rust

Example

import rehypeLumis from '@lumis-sh/rehype-lumis'
import {htmlInline} from '@lumis-sh/lumis/formatters'
import plaintext from '@lumis-sh/lumis/langs/plaintext'
import javascript from '@lumis-sh/wasm-javascript'
import latte from '@lumis-sh/themes/catppuccin_latte'

processor.use(rehypeLumis, {
  formatter: (language) =>
    htmlInline({language, theme: latte}),
  languages: [javascript, plaintext],
})

This plugin replaces pre > code blocks in HAST with Lumis HTML output.

Full pipeline

import {unified} from 'unified'
import remarkParse from 'remark-parse'
import remarkRehype from 'remark-rehype'
import rehypeStringify from 'rehype-stringify'
import rehypeLumis from '@lumis-sh/rehype-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 file = await unified()
  .use(remarkParse)
  .use(remarkRehype)
  .use(rehypeLumis, {
    formatter: (language) =>
      htmlInline({language, theme: latte}),
    languages: [javascript, rust, plaintext],
  })
  .use(rehypeStringify)
  .process(markdown)

Options

  • formatter - required callback that receives the detected block language and returns a Lumis formatter
  • languages - optional language definitions to register up front with createHighlighter
  • defaultLanguage - language for blocks that name none; defaults to "plaintext". Set it to false to leave unlabeled blocks untouched. An omitted or undefined value uses the default.

For example, use defaultLanguage: 'elixir' to highlight unlabeled fences as Elixir. A language named on the block takes precedence.

  • inlineCode - also highlight inline <code> that names its language; defaults to false. See Inline code.

To skip one block, add nohighlight or no-highlight to its <pre> or <code> classes. Either class leaves the block untouched, regardless of its language or the defaultLanguage option.

Inline code

With inlineCode: true, a <code> outside a <pre> is highlighted when it names its language. Inline code that names none is left alone, so prose in backticks is never recolored. In Markdown, end the code span with a {:lang} suffix:

Declare it with `const answer = 42{:javascript}`.

In HTML, or with a remark plugin that adds attributes, use a language-* class or data-language on the <code>:

<code class="language-javascript">const answer = 42</code>

The <code> keeps its attributes, and its text is replaced with the inline structure of the formatter's output. The suffix is removed first. The formatter's theme colors go on the <code> with the lumis class, as a block's <pre> would get them:

<code class="lumis" style="color: #4c4f69; background-color: #eff1f5;"><span style="color: #8839ef;">const</span> …</code>

nohighlight and no-highlight skip inline code too. A formatter that is not one of the built-in HTML formatters leaves inline code alone.

Behavior

  • visits pre elements in HAST whose first child is a code element
  • reads languages from language-* classes on the <code> or <pre> node, or from data-language / language properties
  • replaces each block with Lumis HTML output
  • preserves authored properties on the <pre> and <code> elements, including classes, styles, ids, ARIA attributes, and data attributes, by handing them to the formatter as preAttrs and codeAttrs so class unions and style appends exactly once
  • keeps anything the authored <pre> held after its <code>, such as a copy button another plugin added
  • loads whatever language a fence names from its installed package, the same as every other runtime, so languages is a prefetch list rather than an allow-list
  • a fence naming a language that cannot be loaded renders as plain text with the configured formatter; the rest of the document still renders

Use it in:

  • unified
  • MDX pipelines
  • Next.js MDX
  • Astro markdown and MDX
  • react-markdown

On this page