Light/Dark Dual Themes | Shiki

ID: 1733https://shiki.matsu.io/guide/dual-themes
Source

Light/Dark Dual Themes

Shiki supports outputting light/dark dual or multiple themes.
Shiki's dual‑themes approach uses CSS variables to store the colors on each token.

Change the theme option in codeToHtml to themes with light and dark keys to generate two themes.

import { codeToHtml } from 'shiki'

const code = await codeToHtml(
  'console.log("hello")',
  {
    lang: 'javascript',
    themes: {
      light: 'min-light',
      dark: 'nord',
    }
  }
)

The following HTML will be generated
(demo preview):

<pre
  class="shiki shiki-themes min-light nord"
  style="background-color:#ffffff;--shiki-dark-bg:#2e3440ff;color:#24292eff;--shiki-dark:#d8dee9ff"
  tabindex="0">
  <code>
    <span class="line"><span style="color:#1976D2;--shiki-dark:#D8DEE9">console</span><span style="color:#6F42C1;--shiki-dark:#ECEFF4">.</span><span style="color:#6F42C1;--shiki-dark:#88C0D0">log</span><span style="color:#24292EFF;--shiki-dark:#D8DEE9FF">(</span><span style="color:#22863A;--shiki-dark:#ECEFF4">"hello"</span><span style="color:#24292EFF;--shiki-dark:#D8DEE9FF)"></span></span>
  </code>
</pre>

Query‑based Dark Mode

To make it reactive to your site’s theme, you need to add a short CSS snippet:

@media (prefers-color-scheme: dark) {
  .shiki,
  .shiki span {
    color: var(--shiki-dark) !important;
    background-color: var(--shiki-dark-bg) !important;
    /* Optional, if you also want font styles */
    font-style: var(--shiki-dark-font-style) !important;
    font-weight: var(--shiki-dark-font-weight) !important;
    text-decoration: var(--shiki-dark-text-decoration) !important;
  }
}

Class‑based Dark Mode

html.dark .shiki,
html.dark .shiki span {
  color: var(--shiki-dark) !important;
  background-color: var(--shiki-dark-bg) !important;
  /* Optional, if you also want font styles */
  font-style: var(--shiki-dark-font-style) !important;
  font-weight: var(--shiki-dark-font-weight) !important;
  text-decoration: var(--shiki-dark-text-decoration) !important;
}

Multiple Themes

It’s also possible to support more than two themes.
In the themes object, you can have an arbitrary number of themes, and specify the default theme with defaultColor option.

import { codeToHtml } from 'shiki'

const code = await codeToHtml(
  'console.log("hello")',
  {
    lang: 'javascript',
    themes: {
      light: 'github-light',
      dark: 'github-dark',
      dim: 'github-dimmed',
      // any number of themes
    },
    // optional customizations
    defaultColor: 'light',
    cssVariablePrefix: '--shiki-',
  }
)

span tokens would be generated with respective theme's CSS variables:

<span style="color:#1976D2;--shiki-dark:#D8DEE9;--shiki-dim:#566575">console</span>

After that, you need to apply the theme’s CSS variables on the element with shiki class and tokens under it, for example, based on the parent’s data-theme property:

[data-theme='dark'] .shiki,
[data-theme='dark'] .shiki span {
  background-color: var(--s-dark-bg) !important;
  color: var(--s-dark) !important;
  /* other properties as needed */
}

(The page may contain additional CSS for handling other themes or custom variable prefixes; include them as needed.)