Documentation
@if / @else
Conditionally render components based on state.
Basic Usage
var isLoading = true
@if (isLoading) {
<CircularProgressIndicator />
} else {
<Text>Content loaded!</Text>
} Multiple Conditions
var status: Status = Status.Loading
@if (status == Status.Loading) {
<CircularProgressIndicator />
} else if (status == Status.Success) {
<Text color="#10b981">Success!</Text>
} else {
<Text color="#ef4444">Error</Text>
} Null Checks
var user: User? = null
@if (user != null) {
<Text>Welcome, {user.name}!</Text>
} else {
<Button onClick={() => $navigate("/login")} text="Login" />
} Complex Expressions
var count = 5
var enabled = 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>? = null
var error: String? = null
var isLoading = true
$onMount {
launch {
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()} text="Retry" />
</Column>
} else if (data != null) {
<LazyColumn>
@for (show in data) {
<ShowCard show={show} />
}
</LazyColumn>
} Feature Flags
@if ($env.FEATURE_DARK_MODE) {
<Switch bind:checked={darkMode} label="Dark Mode" />
}
@if ($env.DEBUG) {
<Button onClick={clearCache} text="Clear Cache" />
} Authentication
@if (Auth.isLoggedIn) {
<Column>
<Text>Welcome, {Auth.user.name}!</Text>
<Button onClick={Auth.logout} text="Logout" />
</Column>
} else {
<Column>
<Text>Please log in</Text>
<Button onClick={() => $navigate("/login")} text="Login" />
</Column>
} Empty States
var items: List<Item> = []
@if (items.isEmpty()) {
<Column align="center" p={40}>
<Icon name="inbox" size={64} color="#999" />
<Text fontSize={20} color="#999">No items yet</Text>
<Button text="Add Item" onClick={addItem} />
</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 text="Upgrade to Premium" />
}
} 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 = false
@if (showPanel) {
<Card in:fade={{ duration: 300 }} out:fade={{ duration: 300 }}>
<Text>Panel content</Text>
</Card>
} Complete Example
var searchQuery = ""
var results: List<Show> = []
var isSearching = false
var error: String? = null
suspend fun search() {
if (searchQuery.isEmpty()) {
results = []
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={() => launch { 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