Plus ยท CodeHighlight

CodeHighlight

Highlight code blocks in the page according to syntax

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.


import * as React from 'react'
const Test = ()=>{
    const handleClick = ()=>{
        alert("Click")
    }
    return <div onClick={handleClick}>test</div>
}
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

.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);
        }
    }
}
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

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);
    }
}
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

PropertyDescriptionTypeDefault
codePlain 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.stringsemiGlobalDefault("CodeHighlight", "code")
languageLanguage, which must be registered or passed through languages.stringundefined
lineNumberWhether to show line numbers.booleansemiDefault("CodeHighlight", "lineNumber", true)
languagesExtra 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")
themesReplaces the Shiki themes of this block for light and dark mode.CodeHighlightThemessemiGlobalDefault("CodeHighlight", "themes")

Events

EventDescriptionCallback parameters
None

Slots

SlotDescriptionScope parameters
None

Exposes

NameDescriptionType
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

MethodDescriptionType
CodeHighlight.registerRegisters 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-label or aria-labelledby and no role on the root, the root gets role="group" (a generic element cannot be named); a role you pass wins

Design Tokens