Skip to content

Themes and Styling

Kodemirror replaces CSS-based theming with Kotlin data classes and Compose styling primitives.

Editor theme

The EditorTheme data class controls the editor's visual appearance — background, foreground, cursor, gutter, selection colors, and the text style. Here is the demo's Tokyo Night-inspired custom theme:

private val customTheme = EditorTheme(
    background = Color(0xFF1A1B26),
    foreground = Color(0xFFA9B1D6),
    cursor = Color(0xFFC0CAF5),
    selection = Color(0xFF364A82),
    activeLineBackground = Color(0xFF1E2030),
    gutterBackground = Color(0xFF1A1B26),
    gutterForeground = Color(0xFF3B4261)
)

Apply it as an extension:

        val session = rememberEditorSession(
            doc = SampleDocs.javascript,
            extensions = basicSetup + javascript().extension +
                editorTheme.of(customTheme)
        )

Built-in themes

Two themes are provided out of the box:

  • defaultEditorTheme — dark theme (One Dark-inspired)
  • lightEditorTheme — light theme

The :theme-one-dark module provides a complete oneDark extension that bundles both the editor theme and syntax highlighting colors.

Syntax highlighting

Syntax highlighting colors are separate from the editor theme. They are defined with HighlightStyle, which maps syntax tags to SpanStyle values:

import com.monkopedia.kodemirror.language.*
import com.monkopedia.kodemirror.lezer.highlight.Tags
import androidx.compose.ui.text.SpanStyle

val myHighlighting = HighlightStyle.define(listOf(
    TagStyleSpec(Tags.keyword, SpanStyle(color = Color(0xFFCBA6F7))),
    TagStyleSpec(Tags.string, SpanStyle(color = Color(0xFFA6E3A1))),
    TagStyleSpec(Tags.comment, SpanStyle(color = Color(0xFF6C7086))),
    TagStyleSpec(Tags.number, SpanStyle(color = Color(0xFFFAB387))),
    TagStyleSpec(Tags.variableName, SpanStyle(color = Color(0xFFCDD6F4))),
    TagStyleSpec(Tags.typeName, SpanStyle(color = Color(0xFFF9E2AF))),
    TagStyleSpec(Tags.function(Tags.variableName), SpanStyle(color = Color(0xFF89B4FA)))
))

Apply it with:

syntaxHighlighting(myHighlighting)

Combining theme and highlighting

A complete theme extension bundles both:

val catppuccin = editorTheme.of(myTheme) + syntaxHighlighting(myHighlighting)

This is the same pattern the oneDark extension uses.

Accessing the theme in composables

The theme is distributed via CompositionLocal, so panels, tooltips, and widgets can read it:

@Composable
fun MyPanel() {
    val theme = LocalEditorTheme.current
    Text("Panel", color = theme.foreground)
}

Comparison with upstream CodeMirror

Upstream (CSS) Kodemirror (Compose)
EditorSession.theme({...}) with CSS selectors editorTheme.of(EditorTheme(...))
HighlightStyle.define([{tag, color}]) HighlightStyle.define(listOf(TagStyleSpec(...)))
CSS class names SpanStyle values
--cm-editor-background EditorTheme.background: Color
Applied via DOM class swap Applied via Compose recomposition

Based on the CodeMirror Styling example.