huozhi/sugar-high

Super lightweight code syntax highlighter solution

TypeScript

1,380

432 commits

updated Oct 8, 2026

See the code

README

Sugar High

version downloads

Lightweight syntax highlighting for JavaScript, popular programming languages, and formats commonly generated by coding agents. It runs in browsers and JavaScript runtimes and returns HTML without requiring a DOM.

Sugar High preview

Install

npm install sugar-high

Agent skill

Install Sugar High guidance for an AI coding agent with the Skills CLI:

npx skills add huozhi/sugar-high --skill sugar-high

Highlight code

import { highlight } from 'sugar-high'

const html = highlight('const ready = true')

JavaScript, including JSX, is the default. Pass a canonical name for another built-in language:

highlight('print("hi")', { lang: 'python' })
highlight('{"ready": true}', { lang: 'json' })
highlight('+ added', { lang: 'diff' })

The lang option is typed and accepts canonical names only.

Advanced: normalize extensions and aliases

You do not need lang() when the language is already known. Use it only when input comes from a filename extension, Markdown fence, or another integration. It converts aliases to the canonical name expected by highlight:

import { lang } from 'sugar-high/lang'

lang('py')    // 'python'
lang('bash')  // 'shell'
lang('jsonc') // 'json'
lang('.yml')  // 'yaml'

If you already have a canonical name, pass it directly—lang() is not required.

See the API reference for the complete mapping and normalization behavior.

Built-in languages

javascript, typescript, css, python, c, go, glsl, java, rust, json, diff, shell, cpp, csharp, sql, html, vue, svelte, yaml, markdown, plaintext, ruby, kotlin, swift, php, toml, powershell, dockerfile, graphql, hcl, zig, and lua.

Related dialects share one implementation: JavaScript includes JSX, TypeScript includes TSX, JSON includes JSONC comments, Shell includes sh/Bash/Zsh, HTML currently provides the base highlighting for Vue and Svelte, and HCL includes Terraform.

Composable core

Use sugar-high/core to separate configurable syntax parsing from HTML rendering. It does not include the built-in language registry:

import { parse, render } from 'sugar-high/core'

const parsed = parse('select * from users', {
  keywords: new Set(['select', 'from', 'where']),
})

const html = render(parsed, {
  cx: { keyword: 'font-bold' },
})

If bundle size matters and you only need a few built-in languages, import their configurations directly instead of loading the complete registry from sugar-high or sugar-high/lang:

import { parse, render } from 'sugar-high/core'
import * as css from 'sugar-high/lang/css'
import * as python from 'sugar-high/lang/python'

const languages = { css, python }

const highlight = (code, language) =>
  render(parse(code, languages[language]))

Use the default sugar-high export when you want built-in languages and one-step highlight().

For project-specific GLSL types, copy the built-in configuration before extending its type set:

import { parse, render } from 'sugar-high/core'
import * as glsl from 'sugar-high/lang/glsl'

const shader = {
  ...glsl,
  typeKeywords: new Set([...glsl.typeKeywords, 'myVector']),
}

render(parse('myVector color;', shader))

Customize tokens

Use cx for a class map. It works well with utility CSS, CSS Modules, and global styles while preserving Sugar High's semantic token classes.

highlight(source, {
  lang: 'typescript',
  cx: {
    keyword: 'font-bold',
    comment: 'italic opacity-60',
  },
})

Use mark(token) for conditional classes, inline styles, or custom attributes. It mutates the token and returns nothing:

highlight(source, {
  mark(token) {
    if (token.type === 'comment' && token.value.includes('TODO')) {
      token.className += ' text-orange-500'
      token.properties['data-todo'] = true
    }
  },
})

cx runs before mark, so mark receives the composed class name.

Highlight lines

Use markLine to customize generated lines. Its index is zero-based:

highlight(source, {
  markLine(line) {
    if (line.index === 1) {
      line.className += ' sh__line--highlighted'
    }
  },
})

Style the class with CSS. The React package also provides the one-based highlightLines={[1, [4, 7]]} prop, while the Remark plugin reads ranges from fence metadata such as {2,5-7}.

Styling

Each line uses .sh__line. Token colors use CSS custom properties, so a theme can be embedded in your own stylesheet or scoped to any ancestor:

.code {
  --sh-class: #2d5e9d;
  --sh-identifier: #354150;
  --sh-sign: #8996a3;
  --sh-property: #0550ae;
  --sh-entity: #249a97;
  --sh-jsxliterals: #6266d1;
  --sh-string: #00a99a;
  --sh-keyword: #f47067;
  --sh-comment: #a19595;
}

Lines can be styled or numbered with ordinary CSS:

pre code {
  counter-reset: line;
}

.sh__line {
  display: block;
}

.sh__line::before {
  counter-increment: line;
  content: counter(line);
  margin-right: 1.5rem;
  color: #a4a4a4;
}

.sh__line:nth-child(5),
.sh__line--highlighted {
  background: #fff8c5;
}

React

@sugar-high/react provides a highlighted <Code /> block and textarea-overlay <Editor /> as separate composable exports.

import { Code, Editor } from '@sugar-high/react'

<Editor lang="typescript" value={source} onChange={setSource} />
<Code lang="typescript" lineNumbers>{source}</Code>

Remark

@sugar-high/remark highlights fenced code blocks while processing Markdown. Fence aliases are normalized through the same lang() mapping.

API

See docs/API.md for package exports, the full language mapping, highlighting options, and lower-level functions. Upgrading from v1? Read the v2 migration guide.

Benchmarks

Sugar High, PrismJS, and highlight.js highlighting the same generated TypeScript files:

Measured 2026-09-04 with Node v24.18.0, darwin arm64, Apple M4 Pro.

TypeScriptSugar High 2.2.2PrismJS 1.30.0highlight.js 11.12.0
Minified (KiB)9.9014.6329.54
Gzip (KiB)4.355.4711.12
11 KiB1.781.182.11
100 KiB18.0215.2523.05
500 KiB90.9896.41118.39

Median milliseconds per file; lower is better. 5 timed samples after warmup. Sizes are TypeScript-only browser bundles, minified with Bun; gzip uses level 9. Theme CSS is excluded. Loading and initialization are excluded. Each library highlights the same generated TypeScript into HTML using an explicit language. Grammars and HTML output differ; this is not a measure of highlighting quality or browser rendering speed. Results vary by machine and workload.

Run pnpm --filter sugar-high benchmark:large --write to refresh this table and the website comparison from the same measurement. See benchmark methodology and options.

License

MIT

code-block
code-editor
editor
highlight
highlighter
js
jsx
minimalist
react
remark
remark-plugin
syntax
syntax-highlighting

huozhi/sugar-high

Super lightweight code syntax highlighter solution

TypeScript

1,380

432 commits

updated Oct 8, 2026

See the code

README

Sugar High

version downloads

Lightweight syntax highlighting for JavaScript, popular programming languages, and formats commonly generated by coding agents. It runs in browsers and JavaScript runtimes and returns HTML without requiring a DOM.

Sugar High preview

Install

npm install sugar-high

Agent skill

Install Sugar High guidance for an AI coding agent with the Skills CLI:

npx skills add huozhi/sugar-high --skill sugar-high

Highlight code

import { highlight } from 'sugar-high'

const html = highlight('const ready = true')

JavaScript, including JSX, is the default. Pass a canonical name for another built-in language:

highlight('print("hi")', { lang: 'python' })
highlight('{"ready": true}', { lang: 'json' })
highlight('+ added', { lang: 'diff' })

The lang option is typed and accepts canonical names only.

Advanced: normalize extensions and aliases

You do not need lang() when the language is already known. Use it only when input comes from a filename extension, Markdown fence, or another integration. It converts aliases to the canonical name expected by highlight:

import { lang } from 'sugar-high/lang'

lang('py')    // 'python'
lang('bash')  // 'shell'
lang('jsonc') // 'json'
lang('.yml')  // 'yaml'

If you already have a canonical name, pass it directly—lang() is not required.

See the API reference for the complete mapping and normalization behavior.

Built-in languages

javascript, typescript, css, python, c, go, glsl, java, rust, json, diff, shell, cpp, csharp, sql, html, vue, svelte, yaml, markdown, plaintext, ruby, kotlin, swift, php, toml, powershell, dockerfile, graphql, hcl, zig, and lua.

Related dialects share one implementation: JavaScript includes JSX, TypeScript includes TSX, JSON includes JSONC comments, Shell includes sh/Bash/Zsh, HTML currently provides the base highlighting for Vue and Svelte, and HCL includes Terraform.

Composable core

Use sugar-high/core to separate configurable syntax parsing from HTML rendering. It does not include the built-in language registry:

import { parse, render } from 'sugar-high/core'

const parsed = parse('select * from users', {
  keywords: new Set(['select', 'from', 'where']),
})

const html = render(parsed, {
  cx: { keyword: 'font-bold' },
})

If bundle size matters and you only need a few built-in languages, import their configurations directly instead of loading the complete registry from sugar-high or sugar-high/lang:

import { parse, render } from 'sugar-high/core'
import * as css from 'sugar-high/lang/css'
import * as python from 'sugar-high/lang/python'

const languages = { css, python }

const highlight = (code, language) =>
  render(parse(code, languages[language]))

Use the default sugar-high export when you want built-in languages and one-step highlight().

For project-specific GLSL types, copy the built-in configuration before extending its type set:

import { parse, render } from 'sugar-high/core'
import * as glsl from 'sugar-high/lang/glsl'

const shader = {
  ...glsl,
  typeKeywords: new Set([...glsl.typeKeywords, 'myVector']),
}

render(parse('myVector color;', shader))

Customize tokens

Use cx for a class map. It works well with utility CSS, CSS Modules, and global styles while preserving Sugar High's semantic token classes.

highlight(source, {
  lang: 'typescript',
  cx: {
    keyword: 'font-bold',
    comment: 'italic opacity-60',
  },
})

Use mark(token) for conditional classes, inline styles, or custom attributes. It mutates the token and returns nothing:

highlight(source, {
  mark(token) {
    if (token.type === 'comment' && token.value.includes('TODO')) {
      token.className += ' text-orange-500'
      token.properties['data-todo'] = true
    }
  },
})

cx runs before mark, so mark receives the composed class name.

Highlight lines

Use markLine to customize generated lines. Its index is zero-based:

highlight(source, {
  markLine(line) {
    if (line.index === 1) {
      line.className += ' sh__line--highlighted'
    }
  },
})

Style the class with CSS. The React package also provides the one-based highlightLines={[1, [4, 7]]} prop, while the Remark plugin reads ranges from fence metadata such as {2,5-7}.

Styling

Each line uses .sh__line. Token colors use CSS custom properties, so a theme can be embedded in your own stylesheet or scoped to any ancestor:

.code {
  --sh-class: #2d5e9d;
  --sh-identifier: #354150;
  --sh-sign: #8996a3;
  --sh-property: #0550ae;
  --sh-entity: #249a97;
  --sh-jsxliterals: #6266d1;
  --sh-string: #00a99a;
  --sh-keyword: #f47067;
  --sh-comment: #a19595;
}

Lines can be styled or numbered with ordinary CSS:

pre code {
  counter-reset: line;
}

.sh__line {
  display: block;
}

.sh__line::before {
  counter-increment: line;
  content: counter(line);
  margin-right: 1.5rem;
  color: #a4a4a4;
}

.sh__line:nth-child(5),
.sh__line--highlighted {
  background: #fff8c5;
}

React

@sugar-high/react provides a highlighted <Code /> block and textarea-overlay <Editor /> as separate composable exports.

import { Code, Editor } from '@sugar-high/react'

<Editor lang="typescript" value={source} onChange={setSource} />
<Code lang="typescript" lineNumbers>{source}</Code>

Remark

@sugar-high/remark highlights fenced code blocks while processing Markdown. Fence aliases are normalized through the same lang() mapping.

API

See docs/API.md for package exports, the full language mapping, highlighting options, and lower-level functions. Upgrading from v1? Read the v2 migration guide.

Benchmarks

Sugar High, PrismJS, and highlight.js highlighting the same generated TypeScript files:

Measured 2026-09-04 with Node v24.18.0, darwin arm64, Apple M4 Pro.

TypeScriptSugar High 2.2.2PrismJS 1.30.0highlight.js 11.12.0
Minified (KiB)9.9014.6329.54
Gzip (KiB)4.355.4711.12
11 KiB1.781.182.11
100 KiB18.0215.2523.05
500 KiB90.9896.41118.39

Median milliseconds per file; lower is better. 5 timed samples after warmup. Sizes are TypeScript-only browser bundles, minified with Bun; gzip uses level 9. Theme CSS is excluded. Loading and initialization are excluded. Each library highlights the same generated TypeScript into HTML using an explicit language. Grammars and HTML output differ; this is not a measure of highlighting quality or browser rendering speed. Results vary by machine and workload.

Run pnpm --filter sugar-high benchmark:large --write to refresh this table and the website comparison from the same measurement. See benchmark methodology and options.

License

MIT

code-block
code-editor
editor
highlight
highlighter
js
jsx
minimalist
react
remark
remark-plugin
syntax
syntax-highlighting

Project health

Latest release

2.6.0 · Oct 7, 2026

Releases this year

23

Significant stargazers

(top 24 of 43)

Tommy D. Rossi

1,152 followers · starred Aug 2026

Travis Fischer

4,596 followers · starred Aug 2026

Eduardo San Martin Morote

6,580 followers · starred Aug 2026

Leo Lamprecht

1,749 followers · starred Oct 2025