Documentation
@if / else
Conditionally render components based on state.
Basic Usage
var isLoading = $state(true)
@if (isLoading) {
<CircularProgressIndicator />
} else {
<Text>Content loaded!</Text>
} Multiple Conditions
var status: Status = $state(Status.Loading)
@if (status == Status.Loading) {
<CircularProgressIndicator />
} else if (status == Status.Success) {
<Text color="#10b981">Success!</Text>
} else {
<Text color="#ef4444">Error</Text>
} See it happen
import $lib.components.ui.Button
var isOnline = $state(true)
<Column gap={16}>
@if (isOnline) {
<Text>You're online</Text>
}
<Button onClick={() => isOnline = !isOnline}>Toggle</Button>
</Column>Scroll into view to compile.
A branch with no else renders nothing when the condition is false — there is no empty element left behind.
Null Checks
var user: User? = $state(null)
@if (user != null) {
<Text>Welcome, {user.name}!</Text>
} else {
<Button href="/login">Login</Button>
} Complex Expressions
var count = $state(5)
var enabled = $state(true)
@if (count > 0 && enabled) {
<Text>You have {count} items</Text>
} else if (count == 0) {
<Text>No items</Text>
} else {
<Text>Feature disabled</Text>
} Data Loading Pattern
var data: List<Show>? = $state(null)
var error: String? = $state(null)
var isLoading = $state(true)
$onMount {
try {
data = $fetch("https://api.example.com/shows")
} catch (e: Exception) {
error = e.message
} finally {
isLoading = false
}
}
@if (isLoading) {
<Column align="center">
<CircularProgressIndicator />
<Text>Loading...</Text>
</Column>
} else if (error != null) {
<Column align="center">
<Text color="#ef4444">Error: {error}</Text>
<Button onClick={() => reload()}>Retry</Button>
</Column>
} else if (data != null) {
<LazyColumn>
@for (show in data) {
<ShowCard show={show} />
}
</LazyColumn>
} Feature Flags
@if ($env.PUBLIC_FEATURE_DARK_MODE) {
<Switch bind:checked={darkMode} label="Dark Mode" />
}
@if ($env.PUBLIC_DEBUG) {
<Button onClick={clearCache}>Clear Cache</Button>
} Authentication
@if (Auth.isLoggedIn) {
<Column>
<Text>Welcome, {Auth.user.name}!</Text>
<Button onClick={Auth.logout}>Logout</Button>
</Column>
} else {
<Column>
<Text>Please log in</Text>
<Button href="/login">Login</Button>
</Column>
} Empty States
var items: List<Item> = $state(listOf())
@if (items.isEmpty()) {
<Column align="center" p={40}>
<Icon name="ic:baseline-inbox" size={64} color="#999" />
<Text fontSize={20} color="#999">No items yet</Text>
<Button onClick={addItem}>Add Item</Button>
</Column>
} else {
<LazyColumn>
@for (item in items) {
<ItemCard item={item} />
}
</LazyColumn>
} Nested Conditions
@if (user != null) {
@if (user.isPremium) {
<PremiumBadge />
<Text>Premium features enabled</Text>
} else {
<Button>Upgrade to Premium</Button>
}
} Inline Conditionals
For simple text/values, use ternary operator:
<Text>{count > 0 ? "Items: $count" : "No items"}</Text>
<Icon name={isPlaying ? "pause" : "play"} />
<Text color={status == "success" ? "#10b981" : "#ef4444"}>{status}</Text> Behind the Scenes
Whitehall transpiles @if to Compose conditional composition:
@if (condition) {
<ComponentA />
} else {
<ComponentB />
}
// Becomes:
if (condition) {
ComponentA()
} else {
ComponentB()
} For complex pattern matching with sealed classes, use @when instead.
With Animations
Add transitions to conditionally rendered content:
var showPanel = $state(false)
@if (showPanel) {
<Card in:fade={{ duration: 300 }} out:fade={{ duration: 300 }}>
<Text>Panel content</Text>
</Card>
} Complete Example
var searchQuery = $state("")
var results: List<Show> = $state(listOf())
var isSearching = $state(false)
var error: String? = $state(null)
suspend fun search() {
if (searchQuery.isEmpty()) {
results = listOf()
return
}
isSearching = true
error = null
try {
results = $fetch("https://api.example.com/search?q=$searchQuery")
} catch (e: Exception) {
error = e.message
} finally {
isSearching = false
}
}
<Column p={16} gap={16}>
<TextField
bind:value={searchQuery}
label="Search shows"
onChange={() => search()}
/>
@if (isSearching) {
<Column align="center">
<CircularProgressIndicator />
</Column>
} else if (error != null) {
<Text color="#ef4444">Error: {error}</Text>
} else if (searchQuery.isEmpty()) {
<Text color="#999">Start typing to search</Text>
} else if (results.isEmpty()) {
<Text color="#999">No results found</Text>
} else {
<LazyColumn>
@for (show in results) {
<ShowCard show={show} />
}
</LazyColumn>
}
</Column> See Also
- @when - Pattern matching
- @for - List rendering
- in: / out: - Animations