vue-syntax-highlighter
v1.2.1
Published
A Vue 3 syntax highlighter with pluggable engines, semantic themes, and SSR-first performance.
Downloads
1,296
Maintainers
Readme
vue-syntax-highlighter
A Vue 3 syntax highlighter with pluggable engines, semantic themes, and SSR-first performance.
Documentation · API · API Examples
- Vue-idiomatic API — component props, scoped slots, events, exposed methods, a plugin, a provider, and composables.
- Pluggable engines — Shiki by default; highlight.js through lowlight, a lowlight entry, and Prism through refractor as optional adapters.
- Theme-independent tokens — engines return text plus semantic token types only. Changing a theme never invokes the engine.
- Deterministic SSR — synchronous or preloaded engines render highlighted HTML; async engines render a plain busy shell and upgrade after hydration.
- Bounded performance — provider-scoped LRU cache, request deduplication, theme-free cache keys, offscreen deferral, and virtualization for very long files.
Install
# npm
npm install vue-syntax-highlighter
# pnpm
pnpm add vue-syntax-highlighter
# yarn
yarn add vue-syntax-highlighter
# bun
bun add vue-syntax-highlighterInstall the engine you plan to use:
npm install shiki # default
npm install lowlight highlight.js # highlight.js / lowlight adapters
npm install refractor # Prism adapterVue >=3.4 is the only required peer and is provided by your existing Vue application, so the install commands above intentionally omit it. Engine peers are optional. The package is ESM-only and targets Node >=20.19 for SSR/build tooling. Browsers without light-dark() can import the optional fallback stylesheet after the base stylesheet.
import 'vue-syntax-highlighter/styles.css'Quick start
<script setup lang="ts">
import { SyntaxHighlighter } from 'vue-syntax-highlighter'
const code = `const answer = 42
console.log(answer)`
</script>
<template>
<SyntaxHighlighter :code="code" language="javascript" line-numbers />
</template>Engines
<SyntaxHighlighter :code="code" language="python" engine="shiki" />
<SyntaxHighlighter :code="code" language="python" engine="highlightjs" />
<SyntaxHighlighter :code="code" language="python" engine="lowlight" />
<SyntaxHighlighter :code="code" language="python" engine="prism" />Adapters are separate subpaths and lazy chunks. The default entry keeps built-in engines available through those chunks; vue-syntax-highlighter/core exposes the same API without any built-in engine loader, so pass an explicit engine object when a build must not resolve optional peers. vue-syntax-highlighter/full is equivalent to the default entry.
import { createShikiEngine } from 'vue-syntax-highlighter/engines/shiki'
import { createLowlightEngine } from 'vue-syntax-highlighter/engines/lowlight'
import { createHighlightjsEngine } from 'vue-syntax-highlighter/engines/highlightjs'
import { createPrismEngine } from 'vue-syntax-highlighter/engines/prism'Preload a language to get synchronous highlighting (including SSR):
const engine = await createShikiEngine({ preload: ['typescript'] })Themes
<script setup lang="ts">
import { vshLight } from 'vue-syntax-highlighter/themes/vsh-light'
import { vshDark } from 'vue-syntax-highlighter/themes/vsh-dark'
const themes = { light: vshLight, dark: vshDark }
</script>
<template>
<SyntaxHighlighter :code="code" language="ts" :themes="themes" color-scheme="auto" />
</template>Four built-in themes ship as individual data entries: vsh-light (default), vsh-dark, vsh-paper, and vsh-midnight. They form two matched light/dark pairs. defineTheme creates validated, frozen custom themes.
Theme switching updates CSS custom properties and the scheme attribute only. The token output and engine invocation count do not change.
Opt-in behavior
1.2.0 adds capabilities without changing any existing default. Every option below is off unless you ask for it.
<!-- Remove the provider wrapper while keeping its configuration -->
<SyntaxHighlighterProvider renderless :themes="themes">
<!-- Emit theme variables on the block even inside a wrapper provider -->
<SyntaxHighlighter :code="code" language="ts" theme-scope="self" />
</SyntaxHighlighterProvider><!-- Numeric fixed row metrics for deterministic non-virtual rows -->
<SyntaxHighlighter
:code="code"
language="ts"
:line-height="21"
line-height-mode="fixed"
/>// Keep terminal line breaks in a highlight() result
const result = await block.value?.highlight({
code: 'const x = 1\n',
preserveTrailingNewline: true,
})Pass cacheEngineIdentity to a provider or the plugin when two engine objects share an id and must not share cached results. The default cache key remains byte-identical. Import vue-syntax-highlighter/styles/complete.css when you want the base and fallback rules in one stylesheet without a second request.
The project follows an additive-only version policy: minor releases add opt-ins, and there is no scheduled breaking release or default flip. See the Roadmap.
Performance
- Provider/application-scoped LRU cache (100 entries, 8 MiB character budget by default).
- Cache keys cover engine, options, language, and code, but never the theme.
- Concurrent identical requests share one engine call.
deferwaits forIntersectionObserverbefore loading.virtualizedwithheight, fixedlineHeight, andwrap=falsekeeps only the visible window plus overscan in the DOM for long documents.copy()returns the complete source, not the virtualized window or gutter.
Run pnpm bench for cold highlight and initial SSR render timings on 1k/10k-line inputs.
Exports
vue-syntax-highlighter
vue-syntax-highlighter/core
vue-syntax-highlighter/full
vue-syntax-highlighter/engines/shiki
vue-syntax-highlighter/engines/highlightjs
vue-syntax-highlighter/engines/lowlight
vue-syntax-highlighter/engines/prism
vue-syntax-highlighter/themes
vue-syntax-highlighter/themes/default
vue-syntax-highlighter/themes/vsh-light
vue-syntax-highlighter/themes/vsh-dark
vue-syntax-highlighter/themes/vsh-paper
vue-syntax-highlighter/themes/vsh-midnight
vue-syntax-highlighter/styles.css
vue-syntax-highlighter/styles/fallback.css
vue-syntax-highlighter/styles/complete.css
vue-syntax-highlighter/package.jsonDeep imports into dist/ are blocked.
Development
pnpm install
pnpm build
pnpm typecheck
pnpm test:run
pnpm lint
pnpm size
pnpm check:package
pnpm docs:build
pnpm test:e2eSee the full gate with pnpm verify.
Publishing
GitHub Actions deploys the documentation only. npm publishing is manual from an authenticated local checkout; pushing a v* tag records the release but does not publish to npm. See RELEASING.md for the version/changelog checklist, manual publish commands, and rollback steps.
Deploying the docs
The VitePress site builds to docs/.vitepress/dist. A GitHub Actions workflow in .github/workflows/docs.yml publishes it to GitHub Pages on pushes to main. In the repository's Settings → Pages, choose GitHub Actions as the source. Project pages use /<repository>/ automatically; user/organization pages use /.
Documentation
- Getting Started
- Quick Start
- Basic Usage
- Advanced Usage
- Engines
- Themes
- Performance
- Server Rendering
- API
- API Examples
- Limitations
- Roadmap
Attribution
The semantic token vocabulary is informed by common TextMate, Prism, and highlight.js scope categories. All four built-in palettes are authored for this library, not copied from third-party theme files. Runtime highlighting is provided by the optional peer packages Shiki, highlight.js/lowlight, and refractor, each under its own license. No grammar or theme assets are redistributed by this package.
License
MIT
