npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2025 – Pkg Stats / Ryan Hefner

remark-shiki-highlight-api

v0.3.6

Published

Remark plugin for shiki-highlight-api - replaces traditional Shiki code blocks with CSS Custom Highlight API

Readme

remark-shiki-highlight-api

Remark plugin that replaces traditional Shiki code blocks with CSS Custom Highlight API versions, achieving 80-90% fewer DOM nodes while maintaining identical visual output.

Why?

Traditional syntax highlighting wraps each token in a <span> element, creating thousands of DOM nodes for code-heavy pages. This plugin uses the CSS Custom Highlight API to achieve the same visual result with dramatically fewer nodes.

Performance:

  • Traditional approach: ~10 tokens/line × N lines = thousands of <span> elements
  • Highlight API: 1 text node per line
  • Result: 80-90% fewer DOM nodes

Built on top of shiki-highlight-api.

Installation

npm install remark-shiki-highlight-api shiki-highlight-api shiki

Usage

Basic Usage (Astro)

// astro.config.mjs
import { defineConfig } from 'astro/config';
import { remarkHighlightApi } from 'remark-shiki-highlight-api';

export default defineConfig({
  markdown: {
    remarkPlugins: [remarkHighlightApi],
    syntaxHighlight: false, // Disable Astro's default
  },
});

With Custom Theme

import { remarkHighlightApi } from 'remark-shiki-highlight-api';

export default defineConfig({
  markdown: {
    remarkPlugins: [[remarkHighlightApi, { theme: 'github-dark' }]],
    syntaxHighlight: false,
  },
});

Automatic Language Loading

All Shiki bundled languages load automatically when detected in your markdown. No configuration needed for common languages like Python, Rust, Go, PHP, Ruby, etc.

// astro.config.mjs - works out of the box
import { remarkHighlightApi } from 'remark-shiki-highlight-api';

export default defineConfig({
  markdown: {
    remarkPlugins: [remarkHighlightApi],
    syntaxHighlight: false,
  },
});

Then in your markdown:

```python
def hello():
    print("world")
```

```rust
fn main() {
    println!("Hello");
}
```

Both blocks will highlight automatically.

With Custom Languages

For custom TextMate grammars not included in Shiki:

// custom-languages.js
import { loadCustomLanguage } from 'shiki-highlight-api';
import myGrammar from './my-grammar.tmLanguage.json';

export async function loadCustomLanguages() {
  await loadCustomLanguage({
    ...myGrammar,
    name: 'mylang', // Language ID to use in code blocks
  });
}
// astro.config.mjs
import { remarkHighlightApi } from 'remark-shiki-highlight-api';
import { loadCustomLanguages } from './custom-languages.js';

export default defineConfig({
  markdown: {
    remarkPlugins: [
      [
        remarkHighlightApi,
        {
          theme: 'dark-plus',
          loadLanguages: loadCustomLanguages,
        },
      ],
    ],
    syntaxHighlight: false,
  },
});

The loadLanguages callback runs once before processing any code blocks.

Meta String Syntax

You can add transformer features to individual code blocks using meta string syntax in your markdown code fences. All features from shiki-highlight-api v1.0.0+ are supported.

Line Highlighting

Highlight specific lines using curly braces with line numbers or ranges:

```javascript {1,3}
const a = 1; // highlighted
const b = 2;
const c = 3; // highlighted
```

```javascript {1-3}
const a = 1; // highlighted
const b = 2; // highlighted
const c = 3; // highlighted
```

```javascript {1,3-5,7}
// Mix single lines and ranges
```

Line Numbers

Display line numbers using showLineNumbers or lineNumbers flags:

```javascript showLineNumbers
const x = 1; // Shows line 1
const y = 2; // Shows line 2
```

```javascript lineNumbers:10
const x = 1; // Shows line 10
const y = 2; // Shows line 11
```

Diff Indicators

Show added and removed lines using + and - prefixes:

```javascript +1,2 -4
const a = 1; // + added
const b = 2; // + added
const c = 3;
const d = 4; // - removed
```

Focus Lines

Focus specific lines while blurring others using focus{} syntax:

```javascript focus{2,3}
const a = 1; // blurred
const b = 2; // focused
const c = 3; // focused
const d = 4; // blurred
```

```javascript focus{1-3}
// Focus a range of lines
```

Combined Features

You can combine multiple features in a single code block:

```javascript {1,3} showLineNumbers:10 +1 focus{1-2}
const a = 1; // line 10, highlighted, added, focused
const b = 2; // line 11, focused
const c = 3; // line 12, highlighted, blurred
```

Options

interface RemarkHighlightApiOptions {
  /**
   * Default theme to use for syntax highlighting
   * @default 'dark-plus'
   */
  theme?: string;

  /**
   * Enable line numbers globally for all code blocks
   * Can be overridden per-block using meta string syntax
   * @default false
   */
  lineNumbers?: boolean | { start: number };

  /**
   * Optional function to load custom languages before processing
   * This function will be called once before processing any code blocks
   */
  loadLanguages?: () => Promise<void>;
}

Global Line Numbers

You can enable line numbers globally for all code blocks:

export default defineConfig({
  markdown: {
    remarkPlugins: [
      [
        remarkHighlightApi,
        {
          theme: 'dark-plus',
          lineNumbers: true, // All blocks show line numbers
        },
      ],
    ],
    syntaxHighlight: false,
  },
});

Or set a custom starting line number:

remarkPlugins: [
  [
    remarkHighlightApi,
    {
      lineNumbers: { start: 100 },
    },
  ],
];

Individual code blocks can override the global setting using meta string syntax.

Browser Support

The CSS Custom Highlight API is supported in:

  • Chrome 105+
  • Safari 17.2+
  • Firefox 140+ (with flag in earlier versions)

For browsers without support, the plugin will still generate the HTML but highlighting won't be applied. Consider using traditional Shiki as a fallback for unsupported browsers.

How It Works

  1. During markdown processing, the plugin intercepts code blocks
  2. Uses Shiki to tokenize the code
  3. Generates clean HTML (text nodes only, no spans)
  4. Generates CSS with ::highlight() pseudo-elements
  5. Generates JavaScript to register Range objects with CSS.highlights
  6. Replaces the code block with all three pieces

The result looks identical to traditional Shiki but with dramatically fewer DOM nodes.

Example

Input markdown:

```javascript
function hello() {
  console.log('world');
}
```

Traditional Shiki output: ~15 DOM nodes (spans wrapping each token)

This plugin's output: 3 DOM nodes (one per line) + CSS + registration script

Visual result: Identical

Real-World Usage

This plugin is used in production on Code Like It's 198x, a retro programming education site with hundreds of code samples.

License

MIT

Contributing

Contributions welcome! Please open an issue or PR on GitHub.