API Examples
Every public runtime export and public type has an example here. The reference tables live in API.
Entry points
import { SyntaxHighlighter as CoreHighlighter } from 'vue-syntax-highlighter/core'
import { SyntaxHighlighter as FullHighlighter } from 'vue-syntax-highlighter/full'
const entries = [CoreHighlighter, FullHighlighter]core has no built-in engine loader; pass an explicit engine object. full is equivalent to the default entry.
Component
<script setup lang="ts">
import { ref } from 'vue'
import { SyntaxHighlighter } from 'vue-syntax-highlighter'
import type {
HighlightInput,
HighlighterScopeMode,
LineHeightMode,
LineRenderInfo,
LineSlotProps,
SyntaxHighlighterExposed,
SyntaxHighlighterProps,
ThemeScope,
TokenSlotProps,
} from 'vue-syntax-highlighter'
const block = ref<SyntaxHighlighterExposed>()
const code = 'const answer = 42'
const lineHeightMode: LineHeightMode = 'fixed'
const themeScope: ThemeScope = 'self'
const scopeMode: HighlighterScopeMode = 'renderless'
const input: HighlightInput = { code, preserveTrailingNewline: true }
const props: SyntaxHighlighterProps = {
code,
language: 'typescript',
lineNumbers: true,
startLine: 1,
highlightLines: [[1, 2]],
wrap: false,
lineHeight: 21,
lineHeightMode,
themeScope,
}
const lineProps = (info: LineRenderInfo) => ({ 'data-source-line': info.lineNumber })
const linePayload = (payload: LineSlotProps) => payload.renderTokens()
const tokenPayload = (payload: TokenSlotProps) => payload.renderToken()
</script>
<template>
<button type="button" @click="block?.copy()">Copy</button>
<SyntaxHighlighter ref="block" v-bind="props" :line-props="lineProps">
<template #line="{ lineNumber, highlighted, renderTokens }">
<span :data-source-line="lineNumber" :class="{ highlighted }">
<component :is="() => renderTokens()" />
</span>
</template>
<template #token="{ token, renderToken }">
<span :data-token-type="token.type">
<component :is="() => renderToken()" />
</span>
</template>
</SyntaxHighlighter>
</template>// Slot helper types
import type { LineSlotProps, TokenSlotProps } from 'vue-syntax-highlighter'
const inspectLine = (payload: LineSlotProps) => payload.tokens
const inspectToken = (payload: TokenSlotProps) => payload.token.type
void inspectLine
void inspectTokenEvents
import type {
HighlightedEventContext,
HighlightResult,
SyntaxHighlighterEmits,
} from 'vue-syntax-highlighter'
const emit = ((
event: 'highlighted' | 'error',
payload: HighlightResult | Error,
context?: HighlightedEventContext,
) => {
if (event === 'highlighted') {
console.log(payload as HighlightResult, context)
} else {
console.warn((payload as Error).message)
}
}) as SyntaxHighlighterEmitsIn a template, the callback signature is (result, context):
<SyntaxHighlighter
:code="code"
language="ts"
@highlighted="(result, context: HighlightedEventContext) => console.log(result, context)"
@error="(error) => console.warn(error.message)"
/>Provider
<script setup lang="ts">
import { SyntaxHighlighter, SyntaxHighlighterProvider } from 'vue-syntax-highlighter'
import { vshDark } from 'vue-syntax-highlighter/themes/vsh-dark'
import { vshLight } from 'vue-syntax-highlighter/themes/vsh-light'
const themes = { light: vshLight, dark: vshDark }
</script>
<template>
<SyntaxHighlighterProvider
engine="shiki"
:themes="themes"
color-scheme="auto"
:languages="['javascript', 'typescript']"
:cache-capacity="100"
cache-engine-identity
scope-tag="section"
defer
>
<SyntaxHighlighter :code="one" language="ts" />
<SyntaxHighlighter :code="two" language="ts" />
</SyntaxHighlighterProvider>
</template>Set renderless to drop the wrapper while keeping the same provider configuration:
<SyntaxHighlighterProvider renderless :themes="themes" color-scheme="auto">
<SyntaxHighlighter :code="one" language="ts" theme-scope="self" />
</SyntaxHighlighterProvider>Plugin
import { createApp } from 'vue'
import VueSyntaxHighlighter from 'vue-syntax-highlighter'
import type {
HighlighterOptions,
VueSyntaxHighlighterOptions,
VueSyntaxHighlighterPlugin,
} from 'vue-syntax-highlighter'
const options: VueSyntaxHighlighterOptions = {
engine: 'shiki',
languages: ['javascript', 'typescript'],
}
const baseOptions: HighlighterOptions = options
const plugin: VueSyntaxHighlighterPlugin = VueSyntaxHighlighter
createApp(App).use(plugin, baseOptions).mount('#app')Composable
import { ref } from 'vue'
import { useSyntaxHighlighter } from 'vue-syntax-highlighter'
import type {
UseSyntaxHighlighterOptions,
UseSyntaxHighlighterReturn,
} from 'vue-syntax-highlighter'
const code = ref('const value = 1')
const options: UseSyntaxHighlighterOptions = {
code,
language: 'typescript',
preserveTrailingNewline: true,
}
const state: UseSyntaxHighlighterReturn = useSyntaxHighlighter(options)
state.lines.value
state.loading.value
state.error.value
state.getCopyPayload()
await state.copy()
await state.refresh()
await state.highlight({ code: 'const next = 2', preserveTrailingNewline: false })Compatibility aliases
The aliases remain public for existing consumers. They render the same component with a preset engine:
import { Light, LightAsync, PrismLight, PrismAsync } from 'vue-syntax-highlighter'
const aliases = [Light, LightAsync, PrismLight, PrismAsync]
const prism = PrismLightPrefer the native component:
<SyntaxHighlighter :code="code" language="ts" engine="prism" />Theme helpers
import {
BUILTIN_THEME_REGISTRY,
DEFAULT_THEME,
DEFAULT_THEME_NAME,
defineTheme,
isColorScheme,
} from 'vue-syntax-highlighter'
import type {
ColorScheme,
ThemeColorsInput,
ThemeDefinition,
ThemeInput,
ThemePair,
TokenStyle,
TokenType,
} from 'vue-syntax-highlighter'
const colors: ThemeColorsInput = {
background: '#ffffff',
foreground: '#24292f',
gutter: '#6e7781',
lineHighlight: '#eef2f8',
selection: '#b6d7ff',
}
const keyword: TokenStyle = { color: '#cf222e', fontWeight: '600' }
const key: TokenType = 'keyword'
const input: ThemeInput = {
name: 'brand',
colorScheme: 'light',
colors,
tokens: { [key]: keyword },
}
const theme: ThemeDefinition = defineTheme(input)
const pair: ThemePair = { light: theme, dark: theme }
const scheme: ColorScheme = 'auto'
const validScheme = isColorScheme(scheme)
DEFAULT_THEME
DEFAULT_THEME_NAME
BUILTIN_THEME_REGISTRY['vsh-light']Cache helpers
import {
buildCacheKey,
ResultCache,
stableStringify,
} from 'vue-syntax-highlighter'
import type {
CacheKeyInput,
HighlightCacheLike,
HighlightResult,
ResultCacheOptions,
} from 'vue-syntax-highlighter'
const cacheOptions: ResultCacheOptions = { capacity: 50, maxChars: 4 * 1024 * 1024 }
const cache: HighlightCacheLike = new ResultCache(cacheOptions)
const keyInput: CacheKeyInput = {
engineId: 'shiki',
language: 'typescript',
code: 'const x = 1',
engineIdentity: 1,
}
const key = buildCacheKey(keyInput)
const serialized = stableStringify({ language: 'typescript', options: {} })
const plainResult: HighlightResult = {
lines: [{ tokens: [{ text: 'const x = 1', type: 'plain' }] }],
language: 'typescript',
}
cache.request(key, () => plainResult)
cache.delete(key)
cache.clear()
void serializedEngine contract
import type {
EngineOptions,
HighlightEngine,
HighlightLine,
HighlightRequest,
HighlightResult,
HighlightToken,
} from 'vue-syntax-highlighter'
const token: HighlightToken = { text: 'const', type: 'keyword' }
const line: HighlightLine = { tokens: [token] }
const result: HighlightResult = { lines: [line], language: 'typescript' }
const request: HighlightRequest = {
code: 'const x = 1',
language: 'typescript',
signal: new AbortController().signal,
}
const options: EngineOptions = { flavor: 'neutral' }
const engine: HighlightEngine = {
id: 'custom',
capabilities: { sync: true },
hasLanguage: (language) => language === 'text',
loadLanguage: async () => undefined,
highlight: (input, engineOptions) => ({
lines: input.code.split('\n').map((text) => ({
tokens: text ? [{ text, type: 'plain' as const }] : [],
})),
language: input.language,
meta: { options: engineOptions },
}),
dispose: () => undefined,
}
void request
void options
void resultEngine resolution helpers
import {
BUILTIN_ENGINE_IDS,
EngineManager,
HIGHLIGHTER_CONTEXT,
createHighlighterContext,
isHighlightEngine,
} from 'vue-syntax-highlighter'
import type {
BuiltinEngineId,
EngineChoice,
EngineLoader,
EngineRegistry,
HighlighterContext,
} from 'vue-syntax-highlighter'
import { inject, provide } from 'vue'
const customEngine: HighlightEngine = {
id: 'custom',
highlight: () => ({
lines: [{ tokens: [{ text: 'x', type: 'plain' }] }],
language: 'text',
}),
}
const id: BuiltinEngineId = 'shiki'
const choice: EngineChoice = id
const loader: EngineLoader = async () => customEngine
const registry: EngineRegistry = { custom: loader }
const builtins = BUILTIN_ENGINE_IDS
const manager = new EngineManager(registry)
const loaded = await manager.resolve('custom')
const valid = isHighlightEngine(loaded)
manager.dispose()
const context: HighlighterContext = createHighlighterContext(
{ engine: choice },
undefined,
false,
'renderless',
)
provide(HIGHLIGHTER_CONTEXT, context)
const injected = inject(HIGHLIGHTER_CONTEXT)Shiki adapter
import {
createShikiEngine,
languageAliases,
languageLoaders,
supportedLanguages,
} from 'vue-syntax-highlighter/engines/shiki'
import type {
ShikiEngine,
ShikiEngineOptions,
ShikiLanguageLoader,
ShikiLanguageRegistration,
} from 'vue-syntax-highlighter/engines/shiki'
const options: ShikiEngineOptions = { preload: ['typescript'] }
const engine: ShikiEngine = await createShikiEngine(options)
const registration: ShikiLanguageRegistration = {
name: 'custom',
scopeName: 'source.custom',
patterns: [{ match: '.+', name: 'keyword' }],
}
const loader: ShikiLanguageLoader = async () => registration
engine.registerLanguage('custom', loader)
await engine.loadLanguage('custom')
languageLoaders.javascript
languageAliases.js
supportedLanguages.includes('typescript')highlight.js adapter
import {
createHighlightjsEngine,
} from 'vue-syntax-highlighter/engines/highlightjs'
import type {
HighlightjsEngine,
HighlightjsEngineOptions,
HighlightjsLanguageLoader,
HighlightjsLanguageRegistration,
} from 'vue-syntax-highlighter/engines/highlightjs'
const options: HighlightjsEngineOptions = { preload: ['javascript'] }
const engine: HighlightjsEngine = await createHighlightjsEngine(options)
const grammar: HighlightjsLanguageRegistration = (hljs) => ({
name: 'custom',
keywords: 'const let',
contains: [hljs.C_LINE_COMMENT_MODE],
})
const loader: HighlightjsLanguageLoader = async () => grammar
engine.registerLanguage('custom', loader)lowlight entry
import {
createHighlightjsEngine,
createLowlightEngine,
} from 'vue-syntax-highlighter/engines/lowlight'
import type {
LowlightEngine,
LowlightEngineOptions,
LowlightLanguageLoader,
LowlightLanguageRegistration,
} from 'vue-syntax-highlighter/engines/lowlight'
const options: LowlightEngineOptions = { preload: ['javascript'] }
const engine: LowlightEngine = await createLowlightEngine(options)
const grammar: LowlightLanguageRegistration = (hljs) => ({
name: 'custom',
contains: [hljs.C_LINE_COMMENT_MODE],
})
const loader: LowlightLanguageLoader = async () => grammar
engine.registerLanguage('custom', loader)
const equivalent = await createHighlightjsEngine(options)Prism adapter
import { createPrismEngine } from 'vue-syntax-highlighter/engines/prism'
import type {
PrismEngine,
PrismEngineOptions,
PrismLanguageLoader,
PrismLanguageRegistration,
} from 'vue-syntax-highlighter/engines/prism'
const options: PrismEngineOptions = { preload: ['rust'] }
const engine: PrismEngine = await createPrismEngine(options)
const grammar: PrismLanguageRegistration = {
name: 'custom',
displayName: 'custom',
patterns: [],
}
const loader: PrismLanguageLoader = async () => grammar
engine.registerLanguage('custom', loader)Refractor uses a process-global grammar registry; custom registrations are shared across Prism engine instances and are not removed by dispose(). See Engines.
Theme data entries
import vshLightDefault, { vshLight } from 'vue-syntax-highlighter/themes/default'
import { vshDark, vshMidnight, vshPaper } from 'vue-syntax-highlighter/themes'
import { vshLight as lightEntry } from 'vue-syntax-highlighter/themes/vsh-light'
import { vshDark as darkEntry } from 'vue-syntax-highlighter/themes/vsh-dark'
import { vshPaper as paperEntry } from 'vue-syntax-highlighter/themes/vsh-paper'
import { vshMidnight as midnightEntry } from 'vue-syntax-highlighter/themes/vsh-midnight'
void [
vshLightDefault,
vshLight,
vshDark,
vshMidnight,
vshPaper,
lightEntry,
darkEntry,
paperEntry,
midnightEntry,
]Styles
import 'vue-syntax-highlighter/styles.css'
import 'vue-syntax-highlighter/styles/fallback.css'fallback.css is optional and is a no-op in browsers with light-dark().
To ship the base and fallback rules in one request, opt in to the prebuilt complete stylesheet:
import 'vue-syntax-highlighter/styles/complete.css'styles/complete.css concatenates the minified base stylesheet before the minified fallback rules. It is larger than styles.css, so import it instead of, not in addition to, the other two stylesheets.
Opt-in options
These options are additive and default to the existing behavior:
renderlesson the provider defaults tofalse; enable it to remove the wrapper.themeScopeon the component defaults toinherit;selfmakes the block own its theme.lineHeightModeon the component defaults tovisual;fixedemits numeric row metrics.cacheEngineIdentityon the provider or plugin defaults tofalse; enable it to partition same-idengine objects.preserveTrailingNewlinedefaults tofalseon the exposedhighlight()input and the composable.
Package metadata
import { createRequire } from 'node:module'
const require = createRequire(import.meta.url)
const pkg = require('vue-syntax-highlighter/package.json')
console.log(pkg.version)Theme aliases and slots
Light,LightAsync,PrismLight, andPrismAsyncare shown in Compatibility aliases.LineRenderInfo,LineSlotProps, andTokenSlotPropsare shown in Component.SyntaxHighlighterEmits,SyntaxHighlighterExposed, andHighlightedEventContextare shown in Component.HighlightCacheLikeand cache option types are shown in Cache helpers.EngineChoice,EngineLoader,EngineRegistry,BuiltinEngineId, andHighlighterContextare shown in Engine resolution helpers.ThemeColorsInput,ThemeDefinition,ThemeInput,ThemePair,TokenStyle,TokenType, andColorSchemeare shown in Theme helpers.