CSS Builder
Build a theme stylesheet at runtime in Rust, JavaScript / TypeScript, Elixir, and the CLI.
Lumis ships one CSS file per theme. The CSS builder lets you scope selectors, change the container selector, and add container styles.
The builder works with the same theme data as the bundled files. With no options, it produces the same CSS shape as @lumis-sh/themes/css/<theme>.css.
Options
The npm API uses camelCase. Rust and Elixir use snake_case.
| Option | Default | Use it for |
|---|---|---|
scope | "" | Parent selector prepended to every generated selector. |
containerSelector / container_selector | ".lumis" | Set the selector for the code block container rule. |
containerStyle / container_style | none | Add declarations to the container selector. Use this for layout-related CSS such as padding, border-radius, or overflow-x. If a property already exists, the new value replaces it. |
layout | true | Include the built-in line layout rules in @layer lumis. Set to false when your app supplies its own layout. |
containerStyle / container_style is a list of (property, value) pairs. For example, background-color: var(--code-background) replaces the theme background, while padding: 1rem adds a new declaration.
Token selectors are fixed as l-* classes, matching the built-in htmlLinked formatter output. Line wrappers use l-line, highlighted lines use l-highlighted by default, and line-number themes use l-line-number plus l-line-number-highlighted on highlighted gutters.
Colors without layout
Set layout to false to omit the entire @layer lumis block. Container,
token, and gutter theme styles stay, including italic, bold, and decoration
styles. Any explicit containerStyle / container_style declarations stay too.
Prebuilt CSS files always include layout.
const css = buildCss(frappe, {layout: false})Use your own rules for line layout when disabling it.
Combine scoping and container styles
import {buildCss} from '@lumis-sh/themes'
import frappe from '@lumis-sh/themes/catppuccin_frappe'
const css = buildCss(frappe, {
scope: '.docs-theme',
containerSelector: '.code-block',
containerStyle: [
['background-color', 'var(--code-background)'],
['border-radius', '0.5rem'],
['padding', '1rem'],
],
layout: false,
})The output starts like this:
/* catppuccin_frappe
* revision: e068ab5f8261f23f6f71ffd8791ae40315b77b9c
* license: MIT
*/
.docs-theme .code-block {
color: #c6d0f5;
background-color: var(--code-background);
border-radius: 0.5rem;
padding: 1rem;
}
.docs-theme .l-keyword {
color: #ca9ee6;
}Default output
import {buildCss} from '@lumis-sh/themes'
import frappe from '@lumis-sh/themes/catppuccin_frappe'
const css = buildCss(frappe)The output starts with the theme name, revision and license, then the container .lumis rule, then token rules:
/* catppuccin_frappe
* revision: e068ab5f8261f23f6f71ffd8791ae40315b77b9c
* license: MIT
*/
.lumis {
color: #c6d0f5;
background-color: #303446;
}
.l-keyword {
color: #ca9ee6;
}
.l-string {
color: #a6d189;
}Scope a stylesheet
Use scope when the same page needs more than one theme, or when a code block should inherit theme styles only inside part of your app. Do not include a trailing space; Lumis inserts the descendant combinator for you.
import {buildCss} from '@lumis-sh/themes'
import frappe from '@lumis-sh/themes/catppuccin_frappe'
const css = buildCss(frappe, {
scope: 'html[data-theme="dark"]',
containerStyle: [
['background-color', 'var(--code-background)'],
['border-radius', '0.375rem'],
['padding', '1rem'],
],
})That produces selectors like this:
html[data-theme="dark"] .lumis {
color: #c6d0f5;
background-color: var(--code-background);
border-radius: 0.375rem;
padding: 1rem;
}
html[data-theme="dark"] .l-keyword {
color: #ca9ee6;
}Change the container selector
The container rule uses .lumis by default. Change it when your rendered HTML uses a different wrapper class.
const css = buildCss(frappe, {
containerSelector: '.code-block',
})That changes only the container rule selector:
.code-block {
color: #c6d0f5;
background-color: #303446;
}
.l-keyword {
color: #ca9ee6;
}Other runtimes
Java does not expose the CSS builder yet.