State & Input in Kotlin Desktop: Compose Multiplatform | Lesson 03
Video: State & Input in Kotlin Desktop: Compose Multiplatform | Lesson 03 by Taught by Celeste AI - AI Coding Coach
Watch full page →State & Input in Kotlin Desktop: Compose Multiplatform | Lesson 03
In this lesson, we learn how to manage user input and state in a Compose Desktop application using Kotlin. We build a settings form with various input controls like OutlinedTextField, Checkbox, Switch, and RadioButton, demonstrating state hoisting and immutable state updates with data class copy().
Code
import androidx.compose.foundation.layout.*
import androidx.compose.material3.*
import androidx.compose.runtime.*
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp
// Data class representing the form state
data class SettingsState(
val username: String = "",
val notificationsEnabled: Boolean = false,
val darkMode: Boolean = false,
val favoriteColor: String = "Red"
)
@Composable
fun SettingsForm(
state: SettingsState,
onStateChange: (SettingsState) -> Unit
) {
Column(modifier = Modifier.padding(16.dp)) {
// OutlinedTextField with two-way binding
OutlinedTextField(
value = state.username,
onValueChange = { newValue -> onStateChange(state.copy(username = newValue)) },
label = { Text("Username") },
modifier = Modifier.fillMaxWidth()
)
Spacer(Modifier.height(16.dp))
// Checkbox with checked/onCheckedChange
Row(verticalAlignment = Alignment.CenterVertically) {
Checkbox(
checked = state.notificationsEnabled,
onCheckedChange = { checked -> onStateChange(state.copy(notificationsEnabled = checked)) }
)
Spacer(Modifier.width(8.dp))
Text("Enable notifications")
}
Spacer(Modifier.height(16.dp))
// Switch with checked/onCheckedChange
Row(verticalAlignment = Alignment.CenterVertically) {
Switch(
checked = state.darkMode,
onCheckedChange = { checked -> onStateChange(state.copy(darkMode = checked)) }
)
Spacer(Modifier.width(8.dp))
Text("Dark Mode")
}
Spacer(Modifier.height(16.dp))
// RadioButtons for favorite color selection
val colors = listOf("Red", "Green", "Blue")
Text("Favorite Color:")
colors.forEach { color ->
Row(verticalAlignment = Alignment.CenterVertically) {
RadioButton(
selected = (state.favoriteColor == color),
onClick = { onStateChange(state.copy(favoriteColor = color)) }
)
Spacer(Modifier.width(8.dp))
Text(color)
}
}
}
}
@Composable
fun SettingsScreen() {
// Hoisted state owned by parent
var settingsState by remember { mutableStateOf(SettingsState()) }
SettingsForm(
state = settingsState,
onStateChange = { newState -> settingsState = newState }
)
}
Key Points
- Use OutlinedTextField, Checkbox, Switch, and RadioButton with value/checked and onValueChange/onCheckedChange/onClick callbacks for two-way binding.
- State hoisting means the parent component owns the state and passes it down with callbacks; child components remain stateless.
- Use remember { mutableStateOf() } to create local state inside a composable.
- Update immutable state using data class copy() to create modified copies rather than mutating state directly.
- Iterate over options with forEach to create groups of RadioButtons sharing the same state and onClick handler.