An open API service indexing awesome lists of open source software.

https://github.com/posthtml/posthtml-shiki

Highlight code blocks with PostHTML and Shiki
https://github.com/posthtml/posthtml-shiki

Last synced: 4 months ago
JSON representation

Highlight code blocks with PostHTML and Shiki

Awesome Lists containing this project

README

          


PostHTML

Shiki Plugin


Highlight code with PostHTML and Shiki

[![Version][npm-version-shield]][npm]
[![Build][github-ci-shield]][github-ci]
[![License][license-shield]][license]
[![Downloads][npm-stats-shield]][npm-stats]

## Introduction

- [Installation](#installation)
- [Usage](#usage)
- [Attributes](#attributes)
- [Options](#options)

This is a PostHTML plugin that uses [Shiki](https://shiki.style) to highlight code blocks.

Features:

- [x] Configure [`langs`](#langs)
- [x] Configure [`themes`](#themes)
- [x] [`lang`](#lang) attribute
- [x] [`theme`](#theme) attribute
- [x] [Dual Themes](#theme-1)
- [x] [Wrap in custom tag](#wrap)
- [x] [Default color theme](#default-color)
- [x] [Decorations](#decorations)
- [x] [Transformers](#transformers)
- [x] [Custom themes](#custom-themes)
- [x] [Custom languages](#custom-languages)

Input:

```xml

Hello

```

Output:

```html



<h1 class="text-xl">Hello</h1>

```

## Installation

```
npm i posthtml posthtml-shiki
```

## Usage

Use the `` tag to highlight all code inside it:

```js
import posthtml from 'posthtml'
import shiki from 'posthtml-shiki'

posthtml([
shiki()
])
.process('

Hello

')
.then(result => result.html)
```

## Attributes

You may use certain attributes to configure which themes or language to use.

### `lang`

Alias: `language`

Use the `lang` attribute to specify the language of the code block.

```xml

import { codeToHtml } from 'shiki'

```

### `theme`

Use the `theme` attribute to specify the theme to use.

```xml

Hello

```

### `theme-*`

Shiki's [Dual Themes](https://shiki.style/guide/dual-themes) is supported through `theme-*` attributes:

```xml

Hello

```

> [!NOTE]
> If a `theme` attribute is present, it will override the `theme-*` attributes.

This uses CSS variables to switch between themes, so you'll need to define the CSS variables in your stylesheet.

With media queries:

```css
@media (prefers-color-scheme: dark) {
.shiki,
.shiki span {
color: var(--shiki-dark) !important;
background-color: var(--shiki-dark-bg) !important;
/* Optional, if you also want font styles */
font-style: var(--shiki-dark-font-style) !important;
font-weight: var(--shiki-dark-font-weight) !important;
text-decoration: var(--shiki-dark-text-decoration) !important;
}
}
```

Class-based:

```css
html.dark .shiki,
html.dark .shiki span {
color: var(--shiki-dark) !important;
background-color: var(--shiki-dark-bg) !important;
/* Optional, if you also want font styles */
font-style: var(--shiki-dark-font-style) !important;
font-weight: var(--shiki-dark-font-weight) !important;
text-decoration: var(--shiki-dark-text-decoration) !important;
}
```

### `default-color`

When using multiple themes, you may specify the default color theme for Shiki to use.

The value of the attribute must be the name of one of the `theme-*` attributes, so for example if you have `theme-light` and `theme-dark` attributes, the attribute value must be either `light` or `dark`.

```xml

Hello

```

Shiki relies on CSS specificity and changes the order of the classes on the wrapping `

` tag.

By default, the plugin does not set `default-color`.

### `wrap`

By default, the `` tag will be removed and the code block will be wrapped in a `

` tag. Use the `wrap` attribute to define a custom tag to wrap the code block in.

```xml

import { codeToHtml } from 'shiki'

```

Result:

```html

import { codeToHtml } from 'shiki'

```

> [!IMPORTANT]
> The value of the `wrap` attribute must be a valid tag name, CSS selectors are not supported.

## Options

The plugin accepts an options object as the first argument, which can be used to configure things like the tag name or the options to pass to Shiki.

### `tag`

Type: `string`\
Default: `shiki`

Use the `tag` option to specify the tag name to use.

```js
import posthtml from 'posthtml'
import shiki from 'posthtml-shiki'

posthtml([
shiki({
tag: 'highlight'
})
])
.process('... your code')
.then(result => result.html)
```

### `langs`

Type: `string[]`\
Default: `['html']`

Use the `langs` option to specify the languages for Shiki to load.

It's recommended to load only the languages that you need.

```js
import posthtml from 'posthtml'
import shiki from 'posthtml-shiki'

posthtml([
shiki({
langs: ['html', 'javascript']
})
])
.process(`
... some html
... some js
`)
.then(result => result.html)
```

See the list of [supported languages](https://shiki.style/languages) in Shiki.

#### Custom Languages

You may also load custom languages by passing a TextMate grammar object to the `langs` option.

```js
const customDiffLang = JSON.parse(readFileSync('./custom-diff.json', 'utf8'))

posthtml([
shiki({
langs: [customDiffLang]
})
])
.process(`

- FOO
+ BAR

`)
.then(result => result.html)
```

You must specify the `lang` attribute with the name of the language, and the value must match the `name` property of the TextMate grammar object.

See [tm-grammars](https://github.com/shikijs/textmate-grammars-themes/tree/main/packages/tm-grammars) for examples.

### `themes`

Type: `Array | Array`\
Default: `['nord']`

Use the `themes` option to specify the themes for Shiki to load.

It's recommended to load only the themes that you need.

```js
import posthtml from 'posthtml'
import shiki from 'posthtml-shiki'

posthtml([
shiki({
themes: ['github-light', 'github-dark']
})
])
.process(`
[code]
[code]
`)
.then(result => result.html)
```

See the list of [available themes](https://shiki.style/themes) in Shiki.

> [!NOTE]
> If you don't specify a `theme=""` attribute, the first theme in the `themes` option will be used.

#### Custom Themes

You may also load [custom themes](https://shiki.style/guide/load-theme) by passing a TextMate theme object to the `themes` option:

```js
// Define textmate theme
const myTheme = {
name: 'my-theme',
settings: [
{
scope: ['string'],
settings: {
foreground: '#888'
}
},
]
}

posthtml([
shiki({
themes: [myTheme],
})
])
.process(`[code]`)
.then(result => result.html)
```

If you're loading multiple themes, you will need to specify which theme to use with the `theme=""` attribute. For custom themes, the attribute value must match the name of the theme - in the example above, that would be `my-theme`.

### `wrapTag`

Type: `string|boolean`\
Default: `false`

Use the `wrapTag` option to specify a custom tag to wrap the highlighted code block in.

By default, the plugin does not wrap the code block in any tag.

```js
import posthtml from 'posthtml'
import shiki from 'posthtml-shiki'

posthtml([
shiki({
wrapTag: 'div'
})
])
.process('... your code')
.then(result => result.html)
```

Result:

```html


[highlighted code]

```

### `defaultColor`

Type: `string`\
Default: `undefined`

Use the `defaultColor` option to specify the default color theme for Shiki to use.

The value must be the key name of one of the themes in the `themes` option.

```js
import posthtml from 'posthtml'
import shiki from 'posthtml-shiki'

posthtml([
shiki({
themes: {
light: 'github-light',
dark: 'github-dark',
},
defaultColor: 'dark'
})
])
.process(`

[code]

`)
.then(result => result.html)
```

### `decorations`

Type: `array`\
Default: `[]`

Shiki's [Decorations](https://shiki.style/guide/decorations) are supported through the `decorations` option.

You can use this to wrap custom classes and attributes around character ranges in your code.

```js
import posthtml from 'posthtml'
import shiki from 'posthtml-shiki'

posthtml([
shiki({
decorations: [
{
// line and character are 0-indexed
start: { line: 0, character: 0 },
end: { line: 0, character: 5 },
properties: { class: 'highlighted-word' }
}
]
})
])
.process(`

const foo = 'bar'

`)
.then(result => result.html)
```

The word `const` will be wrapped in a `` tag.

### `transformers`

Type: `array`\
Default: `[]`

Use this option to transform the highlighted code block with Shiki's [Transformers](https://shiki.style/guide/transformers).

```js
import posthtml from 'posthtml'
import shiki from 'posthtml-shiki'
import { transformerNotationHighlight } from '@shikijs/transformers'

posthtml([
shiki({
transformers: [
transformerNotationHighlight(),
{
code(node) {
this.addClassToHast(node, 'custom-class')
},
},
]
})
])
.process(`

const foo = 'bar'
let baz = 'biz' // [!code highlight]

`)
.then(result => result.html)
```

See the docs for [Shiki Transformers](https://shiki.style/guide/transformers) and a list of [common Shiki Transformers](https://shiki.style/packages/transformers).

[npm]: https://www.npmjs.com/package/posthtml-shiki
[npm-version-shield]: https://img.shields.io/npm/v/posthtml-shiki.svg
[npm-stats]: http://npm-stat.com/charts.html?package=posthtml-shiki
[npm-stats-shield]: https://img.shields.io/npm/dt/posthtml-shiki.svg
[github-ci]: https://github.com/posthtml/posthtml-shiki/actions/workflows/nodejs.yml
[github-ci-shield]: https://github.com/posthtml/posthtml-shiki/actions/workflows/nodejs.yml/badge.svg
[license]: ./LICENSE
[license-shield]: https://img.shields.io/npm/l/posthtml-shiki.svg