Theming¶
compose-highlight ships four Highlight.js themes out of the box. Those built-ins are precompiled into Kotlin constants at build time, so they do not parse CSS at runtime.
Built-in themes¶
| Theme | Style | Helper |
|---|---|---|
| Tomorrow | Light | rememberTomorrowTheme() |
| Tomorrow Night | Dark | rememberTomorrowNightTheme() |
| Atom One Dark | Dark | rememberAtomOneDarkTheme() |
| Atom One Light | Light | rememberAtomOneLightTheme() |
Built-in themes (tomorrow, tomorrowNight, atomOneDark, atomOneLight) are fast-path themes:
- No
Contextrequired - No runtime CSS parsing
- Color maps are read from precompiled color maps bundled with the library
Automatic light/dark switching¶
Pass a light and dark theme to HighlightThemeProvider. It picks the right one based on the system isSystemInDarkTheme() value:
import dev.hossain.highlight.ui.HighlightThemeProvider
import dev.hossain.highlight.ui.SyntaxHighlightedCode
import dev.hossain.highlight.ui.rememberTomorrowNightTheme
import dev.hossain.highlight.ui.rememberTomorrowTheme
HighlightThemeProvider(
lightHighlightTheme = rememberTomorrowTheme(),
darkHighlightTheme = rememberTomorrowNightTheme(),
) {
SyntaxHighlightedCode(code = snippet, language = "kotlin")
}
Force a specific theme¶
import dev.hossain.highlight.ui.HighlightThemeProvider
import dev.hossain.highlight.ui.rememberAtomOneLightTheme
HighlightThemeProvider(
darkTheme = false, // always use the light theme
lightHighlightTheme = rememberAtomOneLightTheme(),
darkHighlightTheme = rememberAtomOneLightTheme(),
) { ... }
Custom theme from a Highlight.js CSS file¶
- Download any
.cssfile from highlightjs/highlight.js/src/styles (or create your own). - Place it in
src/main/assets/themes/. - Load it with
HighlightTheme.fromAsset():
import dev.hossain.highlight.engine.HighlightTheme
import dev.hossain.highlight.ui.HighlightThemeProvider
val theme = HighlightTheme.fromAsset(
context = LocalContext.current.applicationContext,
assetPath = "themes/github-dark.css",
name = "github-dark",
)
HighlightThemeProvider(darkHighlightTheme = theme) { ... }
fromAsset() is lazy. CSS parsing happens on first use (theme.colorMap), not at factory-call time.
Note
HighlightTheme.fromAsset() normalizes the passed Context to applicationContext internally.
Passing applicationContext at call sites is still recommended for clarity.
Custom theme from raw CSS¶
Useful when the CSS is fetched remotely or generated at runtime:
import dev.hossain.highlight.engine.HighlightTheme
val rawCss = // ... network fetch or string resource
val theme = HighlightTheme.fromCss(cssText = rawCss, name = "remote-theme")
Custom theme from a color map¶
Maximum flexibility - derive colors from Material 3 dynamic color, user palettes, or brand colors:
import dev.hossain.highlight.engine.HighlightTheme
val lightColors = MaterialTheme.colorScheme
val theme = HighlightTheme.fromColorMap(
name = "material-dynamic-light",
colorMap = mapOf(
"hljs" to SpanStyle(color = lightColors.onSurface, background = lightColors.surface),
"hljs-keyword" to SpanStyle(color = lightColors.primary, fontWeight = FontWeight.Bold),
"hljs-string" to SpanStyle(color = lightColors.tertiary),
"hljs-comment" to SpanStyle(color = lightColors.outline, fontStyle = FontStyle.Italic),
),
backgroundColor = lightColors.surface,
defaultTextColor = lightColors.onSurface,
)
Providing a theme without HighlightThemeProvider¶
For one-off use - pass the theme directly:
import dev.hossain.highlight.ui.SyntaxHighlightedCode
import dev.hossain.highlight.ui.rememberTomorrowTheme
val theme = rememberTomorrowTheme()
SyntaxHighlightedCode(
code = snippet,
language = "python",
theme = theme,
)
This creates a standalone HighlightEngine with its own WebView. Use HighlightThemeProvider when rendering multiple code blocks on the same screen.
Highlight both themes simultaneously¶
For zero-latency theme switching, tokenize once and apply both color maps. Use produceState to keep the work off the UI thread:
import dev.hossain.highlight.ui.rememberHighlightEngine
val engine = rememberHighlightEngine()
val fallback = remember(code) { AnnotatedString(code) }
val themedPair by produceState(fallback to fallback, code) {
engine.highlightBothThemes(
code = code,
language = "kotlin",
lightTheme = lightTheme,
darkTheme = darkTheme,
).onSuccess { value = it.light to it.dark }
}
val (lightAnnotated, darkAnnotated) = themedPair
// Switch between lightAnnotated and darkAnnotated instantly
See rememberHighlightedCodeBothThemes for the ready-made composable helper.