Skip to main content

Light/Dark Mode

The multi-themes formatter renders one HTML block with CSS variables for each theme. You control which theme is active with CSS. There are three approaches, from simplest to most flexible.

1. CSS light-dark() function

The simplest option. The browser switches automatically based on the OS theme. Requires color-scheme: light dark on the root element.

Required CSS for the rendered HTML output:

html {
color-scheme: light dark;
}

That's it for runtimes that support HTML Multi-Themes output. No JavaScript or media queries are needed. lumis4j does not support this formatter, and the CLI only generates the HTML; your app or page still needs to provide the CSS.

import {highlight} from '@lumis-sh/lumis'
import {htmlMultiThemes} from '@lumis-sh/lumis/formatters'
import javascript from '@lumis-sh/lumis/langs/javascript'
import githubLight from '@lumis-sh/themes/github_light'
import githubDark from '@lumis-sh/themes/github_dark'
const html = await highlight(
'const x = 1',
htmlMultiThemes({
language: javascript,
themes: {light: githubLight, dark: githubDark},
defaultTheme: 'light-dark()',
})
)

2. @media (prefers-color-scheme) with CSS variables

Use this when you need more control than light-dark() provides, or when targeting browsers that don't support it yet. The inline styles render the light theme by default, and a media query overrides with dark theme variables.

Required CSS for the rendered HTML output:

@media (prefers-color-scheme: dark) {
.lumis,
.lumis span {
color: var(--lumis-dark) !important;
background-color: var(--lumis-dark-bg) !important;
font-style: var(--lumis-dark-font-style) !important;
font-weight: var(--lumis-dark-font-weight) !important;
text-decoration: var(--lumis-dark-text-decoration) !important;
}
}

For runtimes that support HTML Multi-Themes, default_theme: "light" makes the light theme's colors render as inline styles. The media query then swaps to the dark theme's CSS variables when the OS is in dark mode. lumis4j does not support this formatter, and the CLI only generates the HTML.

import {highlight} from '@lumis-sh/lumis'
import {htmlMultiThemes} from '@lumis-sh/lumis/formatters'
import javascript from '@lumis-sh/lumis/langs/javascript'
import githubLight from '@lumis-sh/themes/github_light'
import githubDark from '@lumis-sh/themes/github_dark'
const html = await highlight(
code,
htmlMultiThemes({
language: javascript,
themes: {light: githubLight, dark: githubDark},
defaultTheme: 'light',
})
)

3. Manual switching with JavaScript

Use this when you want a toggle button or user preference that's independent of the OS setting. Add a class to the root element and target it in CSS.

Required CSS for the rendered HTML output:

html.dark .lumis,
html.dark .lumis span {
color: var(--lumis-dark) !important;
background-color: var(--lumis-dark-bg) !important;
font-style: var(--lumis-dark-font-style) !important;
font-weight: var(--lumis-dark-font-weight) !important;
text-decoration: var(--lumis-dark-text-decoration) !important;
}

Toggle JavaScript:

function setTheme(theme) {
if (theme === 'dark') {
document.documentElement.classList.add('dark')
} else {
document.documentElement.classList.remove('dark')
}
}

This pattern works anywhere you render the generated HTML. In Phoenix LiveView, you'd wire the button to a phx-click event that toggles a class via a JS command. lumis4j does not support HTML Multi-Themes, and the CLI only generates the HTML for another renderer to display.

import {highlight} from '@lumis-sh/lumis'
import {htmlMultiThemes} from '@lumis-sh/lumis/formatters'
import javascript from '@lumis-sh/lumis/langs/javascript'
import githubLight from '@lumis-sh/themes/github_light'
import githubDark from '@lumis-sh/themes/github_dark'
const html = await highlight(
code,
htmlMultiThemes({
language: javascript,
themes: {light: githubLight, dark: githubDark},
defaultTheme: 'light',
})
)

Which approach to use

ApproachWhen to use
light-dark()Simplest. OS-driven. No extra CSS or JS needed.
@media prefers-color-schemeOS-driven but you need the CSS override pattern (wider browser support).
Manual switchingUser-controlled toggle independent of OS setting.