Documentation

@when

A list of conditions in markup. The first one that holds renders; the rest are skipped.

Basic Usage

@when takes no subject. Each branch is a condition, an arrow, and the component to render:

<Column>
  @when {
    status == Status.LOADING -> <CircularProgressIndicator />
    status == Status.ERROR -> <Text>Failed to load</Text>
    else -> <ContentView />
  }
</Column>

Which is Kotlin's subject-less when, and compiles to exactly that:

when {
    status == Status.LOADING -> CircularProgressIndicator()
    status == Status.ERROR -> Text(text = "Failed to load")
    else -> ContentView()
}

The rules

There are three, and the second is the one that catches people:

  • Conditions are ordinary Kotlin. Comparisons, enum equality, null checks, calls — anything that evaluates to a Boolean.
  • A branch renders exactly one component. To show more than one thing, wrap them in a <Column> or <Box>.
  • else is optional. Without it, no branch matching means nothing renders — which is usually what you want in markup, and never a compile error.
Braces around a branch body are a parse error. Coming from Kotlin the reflex is condition -> { … }, and that does not compile here. A branch is one component, written directly after the arrow.

See it happen

StatusPanel.wh
var score = 72

<Column>
  @when {
    score >= 90 -> <Text color="#10b981">A</Text>
    score >= 80 -> <Text color="#10b981">B</Text>
    score >= 70 -> <Text color="#f59e0b">C</Text>
    else -> <Text color="#ef4444">F</Text>
  }
</Column>
Kotlin waiting
Scroll into view to compile.

@when matches conditions top to bottom, and the first true branch wins — like a subject-less Kotlin when.

There is no subject form

Kotlin lets you write when (x) { is Loading -> … }, matching on the type of a subject. Whitehall's @when does not: there is no parenthesised subject and no is pattern. Both are parse errors.

// Does not compile
@when (status) {
  is Loading -> { <Text>Loading</Text> }
}

// Write this instead
@when {
  status is Loading -> <Text>Loading</Text>
}

Sealed class hierarchies still work — you just spell the check as a condition, the same as any other. What you give up is the compiler proving the branches are exhaustive, since a subject-less when used as a statement has nothing to be exhaustive over.

@when or @if

They compile to different Kotlin and neither is a shorthand for the other, but in markup the choice is mostly about how many branches you have.

UseWhen
@if / @elseOne condition, or one condition with a fallback. Branches can hold several components.
@whenThree or more branches over the same value, where a chain of else if would bury the shape.

Common patterns

Loading, error, content

<Box fillMaxSize>
  @when {
    isLoading -> <CircularProgressIndicator />
    error != null -> <Text color="#ef4444">{error}</Text>
    items.isEmpty() -> <Text>Nothing here yet</Text>
    else -> <ItemList items={items} />
  }
</Box>

Order matters, because the first true branch wins. Putting items.isEmpty() above the error check would show an empty state during a failure.

Ranges

@when {
  count == 0 -> <Text>None</Text>
  count < 10 -> <Text>A few</Text>
  else -> <Text>Lots</Text>
}

See Also