The comark/plugins/shiki plugin provides syntax highlighting for code blocks using Shiki. It supports multiple themes, line highlighting, and on-demand language loading.
comark/plugins/highlight is a deprecated alias of comark/plugins/shiki and will be removed in the next major version. Prefer import shiki from 'comark/plugins/shiki'.For a lighter alternative (no TextMate grammars), see comark/plugins/rangi.
shiki is a peer dependency, install it alongside Comark:
npm install shikiUsage
Import themes from @shikijs/themes for type safety and tree-shaking:
import { parseMarkdown } from 'comark'
import shiki from 'comark/plugins/shiki'
import githubLight from '@shikijs/themes/github-light'
import githubDark from '@shikijs/themes/github-dark'
const result = await parseMarkdown(content, {
plugins: [
shiki({
themes: {
light: githubLight,
dark: githubDark
}
})
]
})With framework components:
<script setup lang="ts">
import { Markdown } from '@comark/vue'
import shiki from '@comark/vue/plugins/shiki'
import githubLight from '@shikijs/themes/github-light'
import githubDark from '@shikijs/themes/github-dark'
const plugins = [
shiki({
themes: { light: githubLight, dark: githubDark }
})
]
</script>
<template>
<Suspense>
<Markdown :plugins="plugins">{{ content }}</Markdown>
</Suspense>
</template>
<style scoped>
html.dark .shiki :deep(span) {
color: var(--shiki-dark) !important;
background-color: var(--shiki-dark-bg) !important;
font-style: var(--shiki-dark-font-style) !important;
font-weight: var(--shiki-dark-font-weight) !important;
text-decoration: var(--shiki-dark-text-decoration) !important;
}
</style>import { Markdown } from '@comark/react'
import shiki from '@comark/react/plugins/shiki'
import githubLight from '@shikijs/themes/github-light'
import githubDark from '@shikijs/themes/github-dark'
<Markdown
plugins={[shiki({ themes: { light: githubLight, dark: githubDark } })]}
>
{content}
</Markdown>Features
Dual-Theme Support
Highlight code with different themes for light and dark modes. Both palettes are embedded as CSS custom properties, so there is no flash on theme switch. See all available themes →
shiki({
themes: {
light: githubLight,
dark: githubDark
}
})Language Detection
Comark reads the language from the code fence info string and highlights accordingly. Languages are loaded on demand by default. See all 180+ supported languages →
```typescript
const x: number = 42
```Line Highlighting
Highlight specific lines using {line-numbers} syntax:
```javascript {2-3,5}
function example() {
const a = 1 // highlighted
const b = 2 // highlighted
const c = 3
return a + b + c // highlighted
}
```Lines receive the .highlight class; see Styling for the required CSS.
Filename Metadata
Display a filename label above the code block:
```javascript [server.js]
const app = express()
```Language Loading
Import languages from @shikijs/langs to preload them and gain type safety:
import javascript from '@shikijs/langs/javascript'
import typescript from '@shikijs/langs/typescript'
import python from '@shikijs/langs/python'
shiki({
languages: [javascript, typescript, python]
})languages, unregistered languages are loaded on demand. Use registerDefaultLanguages: false with an explicit languages array for the smallest bundle.Transformers
Pass any Shiki transformer via transformers to add diff annotations, focus lines, or custom classes:
import { transformerNotationDiff } from '@shikijs/transformers'
shiki({
themes: { light: githubLight, dark: githubDark },
transformers: [transformerNotationDiff()]
})The most powerful transformer is @shikijs/twoslash: it runs the TypeScript compiler on your code blocks to add inline type tooltips and error annotations.
Pre Styles
Set preStyles: true to add inline background and foreground colors to <pre> elements based on the active theme.
API
shiki(options?)
Returns a ComarkPlugin that enables Shiki syntax highlighting.
Parameters:
options?- Optional configuration, see Options
Returns: ComarkPlugin
Options
| Option | Type | Default | Description |
|---|---|---|---|
themes | object | Material themes | Light and dark theme registrations |
languages | LanguageRegistration[] | undefined | Languages to preload |
transformers | ShikiTransformer[] | undefined | Shiki transformers applied to every block |
preStyles | boolean | false | Add inline background/foreground styles to <pre> |
registerDefaultLanguages | boolean | true | Register the built-in default language set |
registerDefaultThemes | boolean | true | Register the built-in Material themes |
themes
Theme configuration for light and dark modes. Import from @shikijs/themes.
import githubLight from '@shikijs/themes/github-light'
import githubDark from '@shikijs/themes/github-dark'
shiki({
themes: {
light: githubLight,
dark: githubDark
}
})Default: { light: materialThemeLighter, dark: materialThemePalenight }
languages
Languages to preload. Import from @shikijs/langs. Without this option, languages are loaded on demand.
import javascript from '@shikijs/langs/javascript'
import typescript from '@shikijs/langs/typescript'
shiki({
languages: [javascript, typescript]
})Default: undefined
transformers
An array of Shiki transformers applied to every highlighted block.
import { transformerNotationDiff, transformerNotationHighlight } from '@shikijs/transformers'
shiki({
transformers: [
transformerNotationDiff(), // [!code ++] / [!code --]
transformerNotationHighlight(), // [!code highlight]
]
})Default: undefined
preStyles
Add inline background and foreground color styles to <pre> elements based on the active theme.
shiki({ preStyles: true })Default: false
registerDefaultLanguages
When true, these languages are pre-registered: vue, tsx, svelte, astro, typescript, javascript, mdc, bash, json, yaml. Set to false to control the language set entirely via languages.
shiki({
registerDefaultLanguages: false,
languages: [javascript, typescript]
})Default: true
registerDefaultThemes
When true, material-theme-lighter (light) and material-theme-palenight (dark) are pre-registered. Set to false when using only custom themes.
shiki({
registerDefaultThemes: false,
themes: { light: githubLight, dark: githubDark }
})Default: true
Examples
GitHub Theme
import { parseMarkdown } from 'comark'
import shiki from 'comark/plugins/shiki'
import githubLight from '@shikijs/themes/github-light'
import githubDark from '@shikijs/themes/github-dark'
const result = await parseMarkdown(content, {
plugins: [shiki({ themes: { light: githubLight, dark: githubDark } })]
})Minimal Bundle
Disable defaults and import only what you need:
import javascript from '@shikijs/langs/javascript'
import typescript from '@shikijs/langs/typescript'
import githubDark from '@shikijs/themes/github-dark'
shiki({
registerDefaultLanguages: false,
registerDefaultThemes: false,
languages: [javascript, typescript],
themes: { dark: githubDark }
})With Transformers
import {
transformerNotationDiff,
transformerNotationHighlight,
transformerNotationFocus,
} from '@shikijs/transformers'
shiki({
themes: { light: githubLight, dark: githubDark },
transformers: [
transformerNotationDiff(), // [!code ++] / [!code --]
transformerNotationHighlight(), // [!code highlight]
transformerNotationFocus(), // [!code focus]
]
})See the Twoslash guide for TypeScript-powered type tooltips and error annotations in code blocks.
Live Examples
Vue + Vite Highlight
Vue + Vite Twoslash
Styling
Shiki outputs tokens as <span class="line"> elements inside a <pre class="shiki"> block.
Line Highlight
Lines set with {1,3-5} syntax receive the .highlight class:
.shiki span.line.highlight {
background-color: rgba(255, 255, 0, 0.1);
display: inline-block;
width: calc(100% + 2rem);
margin: 0 -1rem;
padding: 0 1rem;
}Dark Mode
When both light and dark themes are provided, Shiki embeds both palettes as CSS custom properties on every <span>. Activate the dark palette based on your project's dark-mode class:
html.dark .shiki span {
color: var(--shiki-dark) !important;
background-color: var(--shiki-dark-bg) !important;
font-style: var(--shiki-dark-font-style) !important;
font-weight: var(--shiki-dark-font-weight) !important;
text-decoration: var(--shiki-dark-text-decoration) !important;
}In Vue scoped styles, use :deep() to reach Shiki spans:
<style scoped>
html.dark .shiki :deep(span) {
color: var(--shiki-dark) !important;
background-color: var(--shiki-dark-bg) !important;
font-style: var(--shiki-dark-font-style) !important;
font-weight: var(--shiki-dark-font-weight) !important;
text-decoration: var(--shiki-dark-text-decoration) !important;
}
</style>