// Clamp the Courant number before each iteration
const courant = computed(() => Math.min(rawCourant.value, 5));
watch(courant, (value) => {
solver.setMaxCourant(value);
});<script setup>
import { CodeHighlighted, ShikiProvider } from "@dicehub/kappa/components/code-highlighted";
const code = `// Clamp the Courant number before each iteration
const courant = computed(() => Math.min(rawCourant.value, 5));
watch(courant, (value) => {
solver.setMaxCourant(value);
});`;
</script>
<template>
<ShikiProvider :languages="['typescript']">
<CodeHighlighted
title="courant-limit.ts"
:code="code"
lang="typescript"
show-copy-button
/>
</ShikiProvider>
</template>Installation
The component lazy-loads shiki, @shikijs/langs, and@shikijs/themes on first render. Install them alongside@dicehub/kappa; they are optional peers, so applications without code display pay nothing.
Import this optional feature only through its dedicated entry point. The root@dicehub/kappa barrel does not export it.
Dedicated Entry Point
import {
CodeHighlighted,
CodeHighlightedRoot,
ShikiProvider,
useShikiHighlighter,
} from "@dicehub/kappa/components/code-highlighted";Usage
Wrap code blocks in one ShikiProvider per application or subtree. It creates a single shared highlighter and loads only the listed languages. Until the highlighter is ready, blocks render plain text.
interface BoundaryPatch {
name: string;
type: "inlet" | "outlet" | "wall";
faces: number;
}<script setup>
import { CodeHighlighted, ShikiProvider } from "@dicehub/kappa/components/code-highlighted";
const code = `interface BoundaryPatch {
name: string;
type: "inlet" | "outlet" | "wall";
faces: number;
}`;
</script>
<template>
<ShikiProvider :languages="['typescript']">
<CodeHighlighted :code="code" lang="typescript" />
</ShikiProvider>
</template>Composition
CodeHighlighted.Provider
└── CodeHighlighted.RootShiki owns tokenization with TextMate grammars. Kappa owns the provider lifecycle (lazy load, disposal, language sets), the fixed light and dark themes, the display geometry, and semantic tokens. Themes are fixed — github-light andvesper — for consistent rendering in both modes.
ShikiProviderloads the engine, themes, and languages once, then shares them.CodeHighlightedrenders one block; unknown languages degrade to plain text with a warning.useShikiHighlighterexposes the shared highlighter for custom blocks.
Examples
Title
Add a short file name or label with title. The copy control stays visible in the header.
function decompose(mesh: Mesh, partitions: number) {
const regions = mesh.split(partitions);
const balanced = balance(regions);
return balanced.map(assignWeights);
}<CodeHighlighted
title="mesh-partition.ts"
:code="code"
lang="typescript"
show-copy-button
/>Languages
Load exactly the languages an application needs; aliases such as ts or sh resolve automatically.
async function fetchRun(id: string): Promise<SimulationRun> {
const response = await fetch(`/api/runs/${id}`);
return response.json();
}<script setup lang="ts">
const cells = ref(2_400_000);
</script>
<template>
<span>{{ cells }} cells</span>
</template># Build the library and run the docs
pnpm --filter @dicehub/kappa build
pnpm dev{
"solver": "pimpleFoam",
"correctors": 6,
"adaptive": true
}.kappa-code-highlighted {
border: 1px solid var(--kappa-line);
border-radius: 0.5rem;
}<ShikiProvider :languages="['typescript', 'vue', 'bash', 'json', 'css']">
<CodeHighlighted :code="fetchRunSource" lang="typescript" />
<CodeHighlighted :code="sfcSource" lang="vue" />
<CodeHighlighted :code="installCommands" lang="bash" />
<CodeHighlighted :code="solverConfig" lang="json" />
<CodeHighlighted :code="tokenStyles" lang="css" />
</ShikiProvider>Highlight Lines
Emphasize 1-indexed lines with highlightLines.
function decompose(mesh: Mesh, partitions: number) {
const regions = mesh.split(partitions);
const balanced = balance(regions);
return balanced.map(assignWeights);
}<CodeHighlighted :code="code" lang="typescript" :highlight-lines="[3]" />Custom Highlight Color
Override the --kappa-code-highlight-bg token to recolor highlighted lines.
function decompose(mesh: Mesh, partitions: number) {
const regions = mesh.split(partitions);
const balanced = balance(regions);
return balanced.map(assignWeights);
}<template>
<CodeHighlighted
class="accent-lines"
:code="code"
lang="typescript"
:highlight-lines="[3]"
/>
</template>
<style scoped>
.accent-lines {
--kappa-code-highlight-bg: color-mix(in oklab, var(--kappa-accent, #4356e8) 14%, transparent);
}
</style>Line Numbers
Line numbers render for multi-line blocks and stay out of the selection.
import { computed, watch } from "vue";
export function useCourantLimit(raw: Ref<number>) {
const clamped = computed(() => Math.min(raw.value, 5));
watch(clamped, (value) => {
solver.setMaxCourant(value);
});
return clamped;
}<CodeHighlighted :code="code" lang="typescript" show-line-numbers />Copy Button
showCopyButton adds the copy affordance. Single-line blocks keep the button visible inline instead of floating it on hover.
pnpm add @dicehub/kappa<CodeHighlighted code="pnpm add @dicehub/kappa" lang="bash" show-copy-button />Copy Button Labels
The copy button text comes from the provider labels; a block can override them through its own labels prop.
interface BoundaryPatch {
name: string;
type: "inlet" | "outlet" | "wall";
faces: number;
}<ShikiProvider :languages="['typescript']" :labels="{ copy: 'Kopieren', copied: 'Kopiert!' }">
<CodeHighlighted :code="code" lang="typescript" show-copy-button />
</ShikiProvider>Accessibility
- Code renders as a
pre/coderegion; plain text remains available while the highlighter loads. - The optional title renders as a semantic
figcaption. - Line numbers are decorative and hidden from assistive technology.
- The Ark UI copy button has an accessible name and a polite status announcement.
- The button stays visible on touch devices and remains reachable with the keyboard.
API Reference
ShikiProvider
| Prop | Type | Default | Description |
|---|---|---|---|
languages | string[] | required | Languages to load; only these get highlighted. |
engine | "javascript" | "wasm" | "javascript" | Shiki regex engine; JavaScript is smaller, Oniguruma (wasm) is more accurate. |
labels | CodeHighlightedLabels | Copy / Copied! | Copy-button labels for every CodeHighlighted inside. |
CodeHighlighted
| Prop | Type | Default | Description |
|---|---|---|---|
code | string | required | Source text to display. |
lang | LanguageInput | string | required | Language id or alias; must be in the provider languages. |
title | string | — | Optional file name or short label rendered above the code. |
showLineNumbers | boolean | false | Adds a line-number column for multi-line code. |
highlightLines | number[] | [] | 1-indexed lines to emphasize. |
showCopyButton | boolean | false | Shows the copy button; always visible on single-line blocks. |
labels | CodeHighlightedLabels | provider | Overrides provider labels for this block. |
Exports
| Export | Description |
|---|---|
CodeHighlighted | Compound API exposing Root and Provider. |
CodeHighlightedRoot | Unaugmented code display component. |
ShikiProvider | Lazy-loads one shared Shiki highlighter for all child blocks. |
useShikiHighlighter | Access highlight, loading state, and labels inside a provider. |
normalizeCodeHighlightedLanguage | Resolves aliases to supported language ids. |
DEFAULT_CODE_HIGHLIGHTED_LABELS | Default copy-button labels. |
CodeHighlightedLabels | Copy-button label overrides. |
CodeHighlightedProps | Public component props. |
LanguageAlias | Supported shorthand language ids. |
LanguageInput | Supported language ids and aliases. |
ShikiEngine | Supported Shiki engine names. |
ShikiProviderProps | Provider props. |
SupportedLanguage | Languages available through the dedicated entry point. |
UseShikiHighlighterResult | Return type of useShikiHighlighter. |