import androidx.compose.animation.animateColorAsState
import androidx.compose.animation.core.tween
import androidx.compose.foundation.LocalIndication
import androidx.compose.foundation.background
import androidx.compose.foundation.border
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.layout.width
import androidx.compose.foundation.selection.selectable
import androidx.compose.foundation.shape.CircleShape
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.foundation.text.BasicText
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.semantics.Role
import androidx.compose.ui.text.TextStyle
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import com.composeunstyled.SwitchThumb
import com.composeunstyled.UnstyledSwitch
@Composable
fun ToggleSwitchDemo() {
var toggled by remember { mutableStateOf(true) }
Row(
Modifier
.width(300.dp)
.clip(RoundedCornerShape(10.dp))
.selectable(
selected = toggled,
onClick = { toggled = toggled.not() },
interactionSource = null,
role = Role.Switch,
).padding(8.dp),
horizontalArrangement = Arrangement.SpaceBetween,
verticalAlignment = Alignment.CenterVertically,
) {
BasicText("Airplane Mode", style = TextStyle(fontSize = 18.sp))
val animatedColor by animateColorAsState(
if (toggled) Color.Black else Color(0xFFE0E0E0),
)
UnstyledSwitch(
checked = toggled,
onCheckedChange = null,
modifier = Modifier
.width(58.dp)
.height(32.dp)
.clip(RoundedCornerShape(100))
.background(animatedColor, RoundedCornerShape(100))
.border(1.dp, Color(0xFFCACACA), RoundedCornerShape(100)),
indication = LocalIndication.current,
) {
SwitchThumb(
animationSpec = tween(),
modifier = Modifier
.padding(4.dp)
.clip(CircleShape)
.background(Color(0xFFF8FAFC))
.border(1.dp, Color(0xFFCACACA), CircleShape)
.size(24.dp),
)
}
}
}Installation
implementation("com.composables:composeunstyled-toggle-switch")
Anatomy
UnstyledSwitch(
checked = checked,
onCheckedChange = onCheckedChange,
) {
SwitchThumb {
}
}
Concepts
UnstyledSwitchrepresents the interactive switch.SwitchThumbplaces thumb content at the start or end of the switch layout.
Accessibility
Use the onCheckedChange parameter to make the switch interactive. Set it to null only when an accessible parent component owns the toggle interaction.
Code Examples
Toggling a switch
Use the checked and onCheckedChange parameters to control switch state:
var checked by remember { mutableStateOf(false) }
UnstyledSwitch(
checked = checked,
onCheckedChange = { checked = it },
) {
SwitchThumb {
BasicText(if (checked) "On" else "Off")
}
}
Animating the switch thumb
Use the animationSpec parameter on SwitchThumb to change the thumb animation:
UnstyledSwitch(
checked = checked,
onCheckedChange = { checked = it },
) {
SwitchThumb(animationSpec = tween(durationMillis = 200)) {
BasicText(if (checked) "On" else "Off")
}
}
Moving toggle behavior to a parent
Use the onCheckedChange parameter with null when a parent toggleable surface owns the interaction. This is useful when the switch is only the visual control inside a larger row.
Row(
modifier = Modifier.toggleable(
value = checked,
role = Role.Switch,
onValueChange = { checked = it },
),
) {
BasicText("Notifications")
UnstyledSwitch(
checked = checked,
onCheckedChange = null,
) {
SwitchThumb {
BasicText(if (checked) "On" else "Off")
}
}
}
API Reference
UnstyledSwitch
| Parameter | Type | Description |
|---|---|---|
checked |
Boolean |
Whether the switch is on or off. |
onCheckedChange |
((Boolean) -> Unit)? |
Callback when the switch changes state. Pass null when another control owns the interaction. |
modifier |
Modifier |
Modifier to be applied to the switch. |
enabled |
Boolean |
Whether the switch is enabled. |
interactionSource |
MutableInteractionSource? |
Interaction source for press, focus, and drag interactions. |
indication |
Indication? |
Indication used for the switch interaction. |
content |
SwitchScope.() -> Unit |
Content drawn inside the switch scope. |
SwitchScope
| Parameter | Type | Description |
|---|---|---|
checked |
Boolean |
Whether the switch is on or off. |
enabled |
Boolean |
Whether the switch is enabled. |
interactionSource |
MutableInteractionSource |
Interaction source for press, focus, and drag interactions. |
SwitchScope.SwitchThumb
| Parameter | Type | Description |
|---|---|---|
modifier |
Modifier |
Modifier to apply to the thumb container. |
animationSpec |
FiniteAnimationSpec<Dp> |
Animation used when the thumb moves between states. |
content |
() -> Unit |
Thumb content. |