Skip to content

Panels

Panels are UI strips displayed above or below the editor content. The search bar is a common example of a panel.

Showing a panel

Create a Panel with a composable lambda and register it through the showPanel facet:

import com.monkopedia.kodemirror.view.*

val myPanel = Panel(
    top = true,
    content = {
        Text("Hello from the top panel!")
    }
)

val state = EditorState.create(EditorStateConfig(
    extensions = showPanel.of(myPanel)
))

Set top = true for a panel above the editor, or top = false (the default) for one below.

Panel data class

data class Panel(
    val top: Boolean = false,
    val content: @Composable BoxScope.() -> Unit
)

The content lambda is a @Composable BoxScope.() -> Unit — it executes inside a Box, giving access to align(), matchParentSize(), and other BoxScope modifiers. Unlike upstream CodeMirror which uses toDOM(), you build your panel UI with standard Compose components.

Multiple panels

Use the showPanels facet to display several panels at once:

    val topPanel = Panel(top = true) {
        Row(
            modifier = Modifier
                .fillMaxWidth()
                .background(Color(0xFF2C313C))
                .padding(horizontal = 12.dp, vertical = 6.dp)
        ) {
            Text(
                text = "Top Panel: editor-toolbar.js",
                style = MaterialTheme.typography.bodySmall,
                color = Color(0xFFABB2BF)
            )
        }
    }
    val bottomPanel = Panel(top = false) {
        Row(
            modifier = Modifier
                .fillMaxWidth()
                .background(Color(0xFF21252B))
                .padding(horizontal = 12.dp, vertical = 6.dp)
        ) {
            Text(
                text = "Bottom Panel: Ln 1, Col 1 | JavaScript | UTF-8",
                style = MaterialTheme.typography.bodySmall,
                color = Color(0xFF636D83)
            )
        }
    }

Dynamic panels with StateField

Toggle a panel on and off using a StateEffect and StateField:

val togglePanel = StateEffect.define<Boolean>()

val panelState = StateField.define(
    create = { false },
    update = { visible, tr ->
        var result = visible
        for (effect in tr.effects) {
            effect.asType(togglePanel)?.let { e ->
                result = e.value
            }
        }
        result
    }
)

fun createPanelExtension(): Extension {
    return panelState.extension
}

// In your composable, conditionally show the panel based on state:
// val isVisible = view.state.field(panelState)

Toggle with:

view.dispatch(TransactionSpec(
    effects = listOf(togglePanel.of(!view.state.field(panelState)))
))

Facets

Facet Type Description
showPanel Facet<Panel?, Panel?> Show a single panel (first non-null wins)
showPanels Facet<List<Panel>, List<Panel>> Show multiple panels simultaneously

Based on the CodeMirror Panel example.