Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/nuejs/nue/llms.txt

Use this file to discover all available pages before exploring further.

Nueglow is Nue’s built-in syntax highlighter. Where popular tools like Shiki and Prism ship grammar files, theme bundles, and megabytes of JavaScript, Nueglow takes a different approach: it parses code into a handful of semantic HTML elements and lets your CSS do the rest. The entire highlighter — covering every language — weighs under 3KB of CSS with no JavaScript runtime required in the browser.

The problem with existing highlighters

Tools built for code editors carry assumptions that are expensive for websites.

Massive footprint

Shiki ships 14MB across 44 packages. Each language requires its own grammar file with thousands of regex rules. HTML’s grammar alone runs over 2,000 lines.

Theme lock-in

Themes arrive as giant JSON files with 300+ hardcoded colors. Adapting them to your brand means overriding hundreds of color values, often fighting specificity wars.

Editor-first design

These tools were built for VS Code extensions, not websites. Your design system becomes an afterthought — something to work around rather than build on.
Nueglow was built specifically for the web. It assumes you already have a design system and wants to fit into it, not replace it.

Language-agnostic parsing

Rather than maintaining a per-language grammar file, Nueglow recognizes patterns that appear across virtually all programming languages:
  • Strings — single-quoted, double-quoted, and template literals
  • Comments — line comments (//, #, --) and block comments (/* */, <!-- -->, ''', =begin)
  • Keywords — a shared vocabulary of ~50 common words covering 95% of real-world usage
  • Operators and special characters — brackets, operators, punctuation
  • Identifiers — function names, variable assignments, property names
Language-specific behavior is handled through small extension tables rather than full grammars. For example, Python adds None, nonlocal, and lambda to the keyword list; Go adds chan and fallthrough; C++ adds cout, cin, using, and namespace. Special-case rules for CSS (hex colors, !important, custom properties), JSON (key names), and YAML (mapping keys) complete the coverage. This approach supports JavaScript, TypeScript, Python, HTML, CSS, YAML, JSON, Markdown, Bash, SQL, Go, Rust, Ruby, PHP, and more — without a single grammar file.

Semantic HTML output

Nueglow’s output is standard HTML using familiar inline elements. Each element carries meaning about the kind of token it wraps:
HTML elementToken typeExample
<strong>Keywords, HTML tag names, CSS hex colorsconst, <div>, #ff0000
<em>Strings, numeric values, CSS custom properties"hello", 42, --color
<sup>Line and block comments// note, /* block */
<b>Identifiers — variable names, function calls, property accessmyVar, fetch(, obj.key
<i>Operators, brackets, interpolation delimiters{, =>, +
<label>Decorators, annotations, Markdown [section] labels@media, !important
<mark>Highlighted spans (single markers)••result••
<u>Double-marked spans (double markers)••••result••••
<ins>Added lines (diff)Lines prefixed with +
<del>Removed lines (diff)Lines prefixed with -
<dfn>Focused linesLines prefixed with >
<span>Line number wrappersWhen numbered: true
These are the same elements that appear in any HTML document. Your browser’s developer tools show them directly, and your existing CSS reset and typography rules already know how to handle them.

Example: HTML output

Given this JavaScript input:
// Fetch user data
async function getUser(id) {
  const res = await fetch(`/api/users/${id}`)
  return res.json()
}
Nueglow produces output like this:
<code language="js">
<sup>// Fetch user data</sup>
<b>async</b> <b>function</b> <b>getUser</b><i>(</i>id<i>)</i> <i>{</i>
  <b>const</b> res <i>=</i> <b>await</b> <b>fetch</b><i>(</i><em>`/api/users/<i>${</i><b>id</b><i>}</i>`</em><i>)</i>
  <b>return</b> res<i>.</i><b>json</b><i>()</i>
<i>}</i>
</code>
Ten to fifteen distinct elements cover every language. Compare this with Shiki’s output, which wraps each token in a <span> with an inline style attribute containing a hardcoded hex color — locking you to a specific theme and making brand customization nearly impossible.

Styling with CSS custom properties

Nueglow’s stylesheet uses CSS custom properties for every color, so overriding the entire color scheme means setting a handful of variables:
/* Default dark theme variables */
pre {
  --glow-bg-color: #20293a;
  --glow-base-color: #a2aab1;
  --glow-primary-color: #7dd3fc;    /* b  — keywords, identifiers */
  --glow-secondary-color: #f472b6;  /* em — strings, numbers */
  --glow-accent-color: #419fff;     /* strong — tag names, accents */
  --glow-char-color: #64748b;       /* i  — operators, brackets */
  --glow-comment-color: #6f7a7d;    /* sup — comments */
  --glow-special-color: #ffffff;    /* label — decorators */
  --glow-marked-color: #2dd4bf26;   /* mark — highlighted spans */
  --glow-error-color: red;          /* u  — error underlines */
  --glow-counter-color: #475569;    /* span::before — line numbers */
  --glow-padding: 1.5em;
}
To switch to a light theme, you only override the variables — you do not replace the entire stylesheet:
/* Light theme override */
pre {
  --glow-bg-color: #f9f9f9;
  --glow-base-color: #555;
  --glow-primary-color: #0068d6;
  --glow-secondary-color: #bd2864;
  --glow-accent-color: #456aff;
  --glow-special-color: #7820bc;
  --glow-char-color: #8e989c;
  --glow-comment-color: #9aa1a3;
  --glow-counter-color: #bbb;
  --glow-marked-color: #51c6fe29;
}
This is the same mechanism used for dark mode across your entire design system — one token swap, consistent with everything else.

Using Nueglow

Automatic: in Nuemark code blocks

When you write a fenced code block in a .md or .nue file, Nueglow runs automatically. Specify the language after the opening fence:
```js
const greeting = 'hello'
```
Nueglow uses the language hint to apply language-specific rules. If no language is specified, it falls back to universal pattern matching.

Standalone usage

You can call Nueglow directly from JavaScript when building custom tooling or rendering code outside Nuemark:
import { glow } from 'nueglow'

const html = glow(`const x = 42`, { language: 'js' })
// Returns: <code language="js"><b>const</b> x <i>=</i> <em>42</em></code>
The glow function accepts a string of code and an options object:
OptionTypeDefaultDescription
languagestringauto-detectedLanguage hint for keyword lists and special rules
numberedbooleanfalseWrap each line in <span> for line number counters
prefixbooleantrueInterpret +, -, > line prefixes as diff markers
markbooleantrueProcess •• inline highlight markers

Line markers

Nueglow supports diff-style line prefixes in code blocks:
```js
+ const added = true
- const removed = false
> const highlighted = 'look here'
  const normal = 'unchanged'
These map to <ins>, <del>, and <dfn> elements, which Nueglow’s markers stylesheet styles with colored left borders and background tints.

Inline highlights

Wrap text with •• (two bullet characters, Alt+Q) to highlight a span within a line:
const ••result•• = compute()
This produces a <mark> element around result, styled with a subtle background tint defined by --glow-marked-color.

Nueglow vs. Shiki and Prism

Nueglow

Under 3KB for all languages. Semantic HTML output. Zero JavaScript in the browser. Style with CSS custom properties you already control.

Shiki

14MB, 44 packages. One grammar file per language. Themes as JSON with 300+ hardcoded colors. Inline style attributes make design system integration difficult.

Prism

Smaller than Shiki but still grammar-per-language. Themes applied via class names. Customization requires theme forks and class overrides.
If you are migrating from Shiki or Prism, you can drop Nueglow in and style it by setting custom properties on pre. You do not need to touch your templates or Markdown source.

Styling line numbers

Enable line numbers by passing numbered: true to the glow function, or by configuring it in your Nuemark settings. Each line is wrapped in a <span>, and CSS counters do the rest:
pre {
  counter-reset: line-counter 0;
}

pre span {
  counter-increment: line-counter 1;
}

pre span::before {
  content: counter(line-counter);
  color: var(--glow-counter-color, #475569);
  display: inline-block;
  text-align: right;
  padding-right: 1em;
  margin-right: 1em;
  width: 2.5em;
}

/* Highlight line numbers on error lines */
pre span:has(u)::before {
  background-color: var(--glow-error-color, red);
  border-radius: 0.2em;
  font-weight: bold;
  color: white;
}
This is pure CSS — no JavaScript, no DOM manipulation at render time. The counter resets per <pre> block automatically.

Build docs developers (and LLMs) love