Rangi (Highlight)

Lightweight syntax highlighting for code blocks using rangi.

The comark/plugins/rangi plugin highlights code blocks with rangi — a tiny, zero-dependency, fully synchronous highlighter (~13kB with all languages, or ~1.5kB core). Prefer this when bundle size and cold-start matter more than TextMate grammar depth.

rangi is a peer dependency:

terminal
npm install rangi
Use comark/plugins/shiki when you need transformers, Twoslash, or the full VS Code grammar set. Use rangi for a faster, smaller highlighter with built-in light/dark themes.

Usage

import { parseMarkdown } from 'comark'
import rangi from 'comark/plugins/rangi'

const result = await parseMarkdown(content, {
  plugins: [rangi()]
})

With framework components:

<script setup lang="ts">
import { Markdown } from '@comark/vue'
import rangi from '@comark/vue/plugins/rangi'
import { github } from 'rangi/themes'
</script>

<template>
  <Suspense>
    <Markdown :plugins="[rangi({ theme: github })]">{{ content }}</Markdown>
  </Suspense>
</template>

Features

Inline theme colors

Tokens get inline colors — no stylesheet required. Pass a single theme or a { light, dark } pair from rangi/themes (defaults to rangi's built-in light/dark pair):

import { githubDark, githubLight, github } from 'rangi/themes'

// single theme
rangi({ theme: githubDark })

// light/dark pair (ready-made)
rangi({ theme: github })

// or explicit pair — also emits --shiki-dark* vars for class-based dark toggles
rangi({ theme: { light: githubLight, dark: githubDark } })

Comark language

Comark ships its own rangi grammar, registered automatically for the comark, mdc, md and markdown fence languages. It is built on rangi's official markdown grammar and adds the Comark syntax on top:

---
title: Frontmatter is highlighted as YAML
---

# Heading{#slug .lead}

::alert{type="warning" .rounded}
A :icon{name="lucide:check"} inline component, a [span]{.accent},
and a {{ user.name || Anonymous }} binding.

#footer
Named slot body
::

The grammar also has a dedicated entry when you want Comark highlighting with rangi without importing the plugin runtime:

import { tokenize } from 'rangi'
import { comarkLanguages } from 'comark/plugins/rangi/language-comark'

const tokens = tokenize(source, {
  lang: 'comark',
  languages: comarkLanguages
})

comark/plugins/rangi/language-comark contains only the rangi grammar and does not import Shiki. Its default export is the individual comarkLanguage definition; comarkLanguages maps it to all four supported aliases.

Language aliases

Rangi ships aliases built-in (javascriptjs, typescriptts, pythonpy, ymlyaml, …). Comark passes the fence info string straight through. Unknown languages fall back to plain text (no throw).

Line highlighting

Fence info {2-3,5} wraps the code in line spans and marks the selected lines with the .highlight class — same as the Shiki plugin. No lineNumbers option is required.

Pre Styles

Set preStyles: true to add inline background and foreground colors to <pre> elements based on the active theme.


API

rangi(options?)

Returns a ComarkPlugin that enables rangi syntax highlighting.


Options

OptionTypeDefaultDescription
themeShjTheme | { light, dark }rangi default pairInline colors
lineNumbersbooleanfalseAlways wrap each line in <span class="line">
classPrefixstring'shj'Class prefix on the highlighted <pre>
languagesRecord<string, grammar>Extra custom grammars, merged over the Comark ones
preStylesbooleanfalseAdd inline background/foreground styles to <pre>

theme

import { github, atomDark, geist } from 'rangi/themes'

rangi({ theme: github })
rangi({ theme: atomDark })
rangi({ theme: geist }) // light/dark pair

Or a plain object:

rangi({
  theme: {
    name: 'mine',
    scheme: 'dark',
    bg: '#0d1117',
    fg: '#e6edf3',
    tokens: {
      kwd: '#ff7b72',
      str: '#a5d6ff',
      cmnt: '#8b949e',
      num: '#79c0ff',
      func: '#d2a8ff',
    },
  },
})

lineNumbers

When true, each source line is always wrapped in <span class="line"> so CSS gutters can number them. Highlight metadata such as {1,3-5} enables line wrappers automatically, even when this option is false:

rangi({ lineNumbers: true })

Default: false

classPrefix

rangi({ classPrefix: 'code' })
// → class="code shj-lang-js"

languages

Pass custom grammars through to rangi (see rangi docs). They are merged over the built-in Comark grammar, so a key such as md overrides it:

rangi({ languages: { mine: myGrammar } })

preStyles

Add inline background and foreground color styles to <pre> elements based on the active theme.

rangi({ preStyles: true })

Default: false


Examples

Minimal

import { parseMarkdown } from 'comark'
import rangi from 'comark/plugins/rangi'

const result = await parseMarkdown(content, {
  plugins: [rangi()]
})

GitHub dual theme

import { github } from 'rangi/themes'

rangi({ theme: github })

With HTML renderer

import { createHtmlRenderer } from '@comark/html'
import rangi from '@comark/html/plugins/rangi'
import { githubDark } from 'rangi/themes'

const renderHtml = createHtmlRenderer({
  plugins: [rangi({ theme: githubDark })],
})

Live Example

Vue + Vite Rangi

Rangi dual themes as inline colors, line highlights, light/dark toggle.

Styling

Colors are inlined on tokens. For dual themes with a class-based dark toggle:

html.dark .shj span {
  color: var(--shiki-dark) !important;
}
html.dark pre.shj {
  background-color: var(--shiki-dark-bg) !important;
  color: var(--shiki-dark) !important;
}

Line highlight

.shj span.line.highlight {
  background-color: rgba(255, 255, 0, 0.1);
  display: inline-block;
  width: calc(100% + 2rem);
  margin: 0 -1rem;
  padding: 0 1rem;
}

Supported languages

46 languages including js/javascript, ts/typescript, tsx, jsx, py/python, rs/rust, go, vue, svelte, astro, css, html, json, yaml/yml, bash/sh/shell, and more — plus Comark itself under comark/mdc/md/markdown.

Full list: rangi languages.