Expressions in Kotlin
Layer properties in MapLibre are not plain values. Each property takes an
expression: a formula that the map evaluates while it renders, per feature and
per zoom level. The MapLibre Style Specification defines
expressions as JSON arrays. MapLibre Compose provides a Kotlin DSL that builds
them with type checking, in org.maplibre.compose.expressions.dsl.
The DSL uses Compose types when a Compose type matches the property: Dp for
sizes, Color for colors, and DpOffset for offsets.
Constants
Section titled “Constants”A constant value must also be an expression. Wrap a plain value in
const:
val state = rememberMapState { val earthquakes = rememberGeoJsonSource( GeoJsonData.Uri("https://maplibre.org/maplibre-gl-js/docs/assets/earthquakes.geojson") )
CircleLayer( id = "quakes-constant", source = earthquakes, radius = const(4.dp), color = const(Color.Red), )}MaplibreMap(state = state)Read feature data
Section titled “Read feature data”feature accesses the properties of the feature being rendered.
The result is untyped, so convert it with functions such as asNumber() or
asString(). Functions such as step and switch
select an output from the value:
val state = rememberMapState { CircleLayer( id = "quakes-by-magnitude", source = earthquakes, radius = step( input = feature["mag"].asNumber(), fallback = const(4.dp), 4 to const(8.dp), 6 to const(16.dp), ), color = switch( condition(test = feature["mag"].asNumber() gt const(5), output = const(Color.Red)), fallback = const(Color.Yellow), ), )}MaplibreMap(state = state)The map evaluates this formula once per feature: each earthquake receives a radius and a color computed from its own magnitude.
React to zoom
Section titled “React to zoom”zoom is the current zoom level. interpolate computes
a smooth value between stops:
val state = rememberMapState { CircleLayer( id = "quakes-by-zoom", source = earthquakes, radius = interpolate( type = exponential(2f), input = zoom(), 5 to const(2.dp), 10 to const(8.dp), ), )}MaplibreMap(state = state)Filter features
Section titled “Filter features”The filter parameter takes a boolean expression. The layer renders only the
features for which it is true:
val state = rememberMapState { CircleLayer( id = "large-quakes", source = earthquakes, filter = feature["mag"].asNumber() gt const(5), )}MaplibreMap(state = state)Missing data
Section titled “Missing data”A feature property can be absent, so feature["place"] has the type
Expression<AnyValue?>: the type is unknown and the value may be null. A
nullable type argument follows Kotlin’s rule. Expression<StringValue?> may
evaluate to null and Expression<StringValue> may not.
An assertion such as asString() aborts the expression for a feature without
the property, and the map draws the property’s default instead. Where a null is
acceptable, keep the nullable type: a text or image property renders a null as
nothing, and eq, neq, and switch on a value handle it. Where a value is
required, supply one with coalesce and a fallback, or with the
fallback argument of an assertion such as asNumber(const(0f)).
val state = rememberMapState { SymbolLayer( id = "quake-places", source = earthquakes, // A missing "place" renders as no text. textField = feature["place"].cast<StringValue?>(), ) CircleLayer( id = "quakes-with-fallback", source = earthquakes, // A missing "mag" counts as 1. radius = coalesce(feature["mag"].cast<FloatValue?>(), fallback = const(1f)).dp, filter = feature["place"] neq nil(), )}MaplibreMap(state = state)nil is a null literal. MapLibre accepts it only where the
expected type is unknown, such as in a comparison. To leave a layer property
unset, pass Kotlin null to the layer.
Where the code runs
Section titled “Where the code runs”Kotlin code outside an expression runs during composition and produces an
expression. The expression runs inside the map renderer, once per feature. A
Kotlin if selects which expression to build; an expression switch selects
a value per feature. Use Kotlin for decisions that depend on app state, and
expressions for decisions that depend on feature data or zoom.
The API reference documents the full set of expression functions under
org.maplibre.compose.expressions.dsl.