When to use
Semi CodeHighlight component is built on Shiki, which uses the same TextMate grammars as VS Code. The languages to highlight are registered by the application, so the bundle only contains the grammars it registers; an unregistered language is shown as plain text. Colors default to Shiki's built-in github-light and github-dark themes, follow Semi's light and dark mode, and can be replaced with other themes.
Demos
How to introduce
<script setup lang="ts">
import { CodeHighlight } from '@fibrous/semi-ui-vue';
</script>
Register languages and themes
Grammars and themes come from the shiki package, so install shiki in the project first. Call CodeHighlight.register once at the application entry: every CodeHighlight can then use those languages.
A language passed as () => import(...) is fetched when the first code block is highlighted, and then every registered language is fetched, not only the one that block uses. Available languages, their names and aliases are listed in the Shiki language list, and themes in the Shiki theme list. Blocks mounted before the registration highlight again once it happens.
import { CodeHighlight } from '@fibrous/semi-ui-vue';
CodeHighlight.register({
languages: [() => import('shiki/langs/javascript.mjs'), () => import('shiki/langs/css.mjs')],
// optional, replaces the default github-light and github-dark
themes: { light: () => import('shiki/themes/min-light.mjs'), dark: () => import('shiki/themes/nord.mjs') },
});
Basic usage
Pass the code plain text to code, and the name or alias of a registered language to language.
Code
<script setup lang="ts">
import { CodeHighlight } from '@fibrous/semi-ui-vue';
const code = `
import * as React from 'react'
const Test = ()=>{
const handleClick = ()=>{
alert("Click")
}
return <div onClick={handleClick}>test</div>
}`;
</script>
<template>
<CodeHighlight :code="code" language="javascript" />
</template>CSS
Code
<script setup lang="ts">
import { CodeHighlight } from '@fibrous/semi-ui-vue';
const code = `.grid {
.semi-row,
.semi-row-flex {
text-align: center;
.semi-col {
min-height: 30px;
line-height: 30px;
background: var(--semi-color-primary-light-default);
outline: 1px solid var(--semi-color-primary-light-active);
}
}
}
`;
</script>
<template>
<CodeHighlight :code="code" language="css" />
</template>Languages for a single block
A language only a few blocks need can be passed to those blocks through languages instead of being registered for the whole application; themes likewise replaces the themes of one block. Declare both values outside the component, so a new array or object on every render does not trigger another highlight. For example, to highlight the Vala language used to write the front-end UI of GTK programs
Code
<script setup lang="ts">
import { CodeHighlight } from '@fibrous/semi-ui-vue';
// declared at the top level so the array is not new on every render, which would highlight again
const languages = [() => import('shiki/langs/vala.mjs')];
const code = `public class ExampleApp : Gtk.Application {
public ExampleApp () {
Object (application_id: "com.example.App");
}
public override void activate () {
var win = new Gtk.ApplicationWindow (this);
var btn = new Gtk.Button.with_label ("Hello World");
btn.clicked.connect (win.close);
win.child = btn;
win.present ();
}
public static int main (string[] args) {
var app = new ExampleApp ();
return app.run (args);
}
}
`;
</script>
<template>
<CodeHighlight :code="code" language="vala" :languages="languages" />
</template>API
Props
| Property | Description | Type | Default |
|---|---|---|---|
| code | Plain text of the code, treated as an empty string when omitted. After code changes the new text shows first and is replaced once highlighting finishes. | string | semiGlobalDefault("CodeHighlight", "code") |
| language | Language, which must be registered or passed through languages. | string | undefined |
| lineNumber | Whether to show line numbers. | boolean | semiDefault("CodeHighlight", "lineNumber", true) |
| languages | Extra Shiki grammars for this block; once loaded, other blocks can use them too. Declare it at the top level of script setup, not as an inline array in the template, which would highlight again on every render. | LanguageInput[] | semiGlobalDefault("CodeHighlight", "languages") |
| themes | Replaces the Shiki themes of this block for light and dark mode. | CodeHighlightThemes | semiGlobalDefault("CodeHighlight", "themes") |
Events
| Event | Description | Callback parameters |
|---|---|---|
| None |
Slots
| Slot | Description | Scope parameters |
|---|---|---|
| None |
Exposes
| Name | Description | Type |
|---|---|---|
| None |
class, style and native attributes land on the root element through attrs. The root element is replaced between the plain-text and the highlighted render ($el is not stable), and these attributes are applied again to the new root each time. A ref or reactive value is fine for languages and themes: the component passes the raw object to Shiki.
Static methods
| Method | Description | Type |
|---|---|---|
| CodeHighlight.register | Registers languages for every CodeHighlight and replaces the default themes; can be called repeatedly, languages add up and themes override | (options: { languages?: LanguageInput[]; themes?: { light?: ThemeInput; dark?: ThemeInput } }) => void |
Accessibility
- With
aria-labeloraria-labelledbyand noroleon the root, the root getsrole="group"(a generic element cannot be named); aroleyou pass wins