Switch
A toggle switch component for binary on/off states. Features smooth animations, different sizes, labels, disabled state, and customizable positioning.
Use on_change for requested values. The owner stores the value and calls cx.notify(). The existing on_click name remains a compatibility alias; setting either replaces the same handler, so the last call wins.
#Import
use gpui_kit::component::switch::Switch;// Installed in ui/components. That directory is on the Slint include path, so import by file name:
import { Switch } from "switch.slint";use iced::widget::{column, container, mouse_area, row, scrollable, svg, text};
use iced::{Alignment, Element, Length, Task, Theme};#Usage
// The value is the caller's: `new(checked)` reads it and `on_toggle` reports
// the requested new one, which the owner writes back.
let usage = column![
Switch::new(app.usage)
.label("Enable notifications")
.on_toggle(Message::Usage),
text(format!("Notifications are {}.", on_off(app.usage))),
]
.spacing(8.0);#Basic
Switch::new("my-switch")
.checked(false)
.on_change(|checked, _, _| {
println!("Switch is now: {}", checked);
})Switch {
label: "Airplane mode";
}
Switch {
label: "Wi-Fi";
checked: true;
}
Switch {
label: "Disabled";
enabled: false;
}let basic = column![
Switch::new(app.airplane)
.label("Airplane mode")
.on_toggle(Message::Airplane),
Switch::new(app.wifi)
.label("Wi-Fi")
.on_toggle(Message::Wifi),
// No message: the switch cannot be pressed, and iced draws it disabled.
Switch::new(false).label("Disabled"),
]
.spacing(12.0);#Sizes
// Small switch
Switch::new("small-switch")
.small()
.label("Small switch")
// Medium switch (default)
Switch::new("medium-switch")
.label("Medium switch")
// Using explicit size
Switch::new("custom-switch")
.with_size(Size::Small)
.label("Custom size")GridLayout {
horizontal-stretch: 1;
spacing: 16px;
Switch {
horizontal-stretch: 0;
size: ControlSize.xsmall;
checked: true;
}
Switch {
horizontal-stretch: 0;
size: ControlSize.small;
checked: true;
}
Switch {
horizontal-stretch: 0;
checked: true;
}
Switch {
horizontal-stretch: 0;
size: ControlSize.large;
checked: true;
}
}// The track is 28×16 for the two small steps and 36×20 for the two large
// ones; the thumb follows at 12 and 16.
let sizes = row![
Switch::new(app.size_xs)
.size(ControlSize::XSmall)
.on_toggle(Message::SizeXs),
Switch::new(app.size_sm)
.size(ControlSize::Small)
.on_toggle(Message::SizeSm),
Switch::new(app.size_md)
.size(ControlSize::Medium)
.on_toggle(Message::SizeMd),
Switch::new(app.size_lg)
.size(ControlSize::Large)
.on_toggle(Message::SizeLg),
]
.spacing(16.0);#Controlled Switch
struct MyView {
is_enabled: bool,
}
impl Render for MyView {
fn render(&mut self, _: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
Switch::new("switch")
.checked(self.is_enabled)
.on_change(cx.listener(|view, checked, _, cx| {
view.is_enabled = *checked;
cx.notify();
}))
}
}#With Label
Switch::new("notifications")
.label("Enable notifications")
.checked(true)
.on_change(|checked, _, _| {
println!("Notifications: {}", if *checked { "enabled" } else { "disabled" });
})VerticalLayout {
spacing: 10px;
alignment: start;
Switch {
label: "Send anonymous usage data";
checked: true;
}
Switch {
label: "Keep the window on top of others";
}
Switch {
label: "Reopen the last workspace on launch";
checked: true;
}
}let labels = column![
Switch::new(app.anonymous)
.label("Send anonymous usage data")
.on_toggle(Message::Anonymous),
Switch::new(app.on_top)
.label("Keep the window on top of others")
.on_toggle(Message::OnTop),
Switch::new(app.reopen)
.label("Reopen the last workspace on launch")
.on_toggle(Message::Reopen),
]
.spacing(10.0);#Disabled State
// Disabled unchecked
Switch::new("disabled-off")
.label("Disabled (off)")
.disabled(true)
.checked(false)
// Disabled checked
Switch::new("disabled-on")
.label("Disabled (on)")
.disabled(true)
.checked(true)VerticalLayout {
spacing: 10px;
alignment: start;
Switch {
label: "Off and disabled";
enabled: false;
}
Switch {
label: "On and disabled";
checked: true;
enabled: false;
}
}let disabled = column![
Switch::new(false).label("Off and disabled"),
Switch::new(true).label("On and disabled"),
]
.spacing(10.0);#Custom Color
Use .color() to override the checked-state background color. The disabled alpha is applied automatically on top of the custom color.
// Success color when checked
Switch::new("switch")
.label("Success")
.checked(true)
.color(cx.theme().success)
// Danger color when checked
Switch::new("switch")
.label("Danger")
.checked(true)
.color(cx.theme().danger)
// Custom color + disabled: color is shown at 50% opacity
Switch::new("switch")
.label("Disabled")
.checked(true)
.color(cx.theme().success)
.disabled(true)#With Tooltip
Switch::new("switch")
.label("Airplane mode")
.tooltip("Enable airplane mode to disable all wireless connections")
.checked(false)#Keyboard Focus
A switch is a tab stop and draws the theme’s focus ring around its track when it is focused, the same ring Checkbox and Button draw. Pass focus_ring(false) when the ring is drawn elsewhere, and tab_stop / tab_index to change its place in the tab order.
Switch::new("switch")
.label("Custom tab order")
.tab_index(2)
.tab_stop(true)
// The row around it draws its own focus treatment.
Switch::new("switch")
.label("Quiet focus")
.focus_ring(false)#Settings Panel
struct SettingsView {
marketing_emails: bool,
security_emails: bool,
push_notifications: bool,
}
v_flex()
.gap_4()
.child(
// Setting with description
v_flex()
.gap_2()
.child(
h_flex()
.items_center()
.justify_between()
.child(
v_flex()
.child(Label::new("Marketing emails").text_lg())
.child(
Label::new("Receive emails about new products and features")
.text_color(theme.muted_foreground)
)
)
.child(
Switch::new("marketing")
.checked(self.marketing_emails)
.on_change(cx.listener(|view, checked, _, cx| {
view.marketing_emails = *checked;
cx.notify();
}))
)
)
)
.child(
// Simple setting
h_flex()
.items_center()
.justify_between()
.child(Label::new("Push notifications"))
.child(
Switch::new("push")
.checked(self.push_notifications)
.on_change(cx.listener(|view, checked, _, cx| {
view.push_notifications = *checked;
cx.notify();
}))
)
)#Compact Settings List
v_flex()
.gap_3()
.child(
Switch::new("wifi")
.label("Wi-Fi")
.label_side(Side::Left)
.checked(true)
.small()
)
.child(
Switch::new("bluetooth")
.label("Bluetooth")
.label_side(Side::Left)
.checked(false)
.small()
)
.child(
Switch::new("airplane")
.label("Airplane Mode")
.label_side(Side::Left)
.checked(false)
.disabled(true)
.small()
)#Form Integration
struct FormData {
subscribe_newsletter: bool,
enable_notifications: bool,
remember_me: bool,
}
v_flex()
.gap_4()
.p_4()
.border_1()
.border_color(theme.border)
.rounded(theme.radius)
.child(
Switch::new("newsletter")
.label("Subscribe to newsletter")
.checked(self.subscribe_newsletter)
.tooltip("Receive monthly updates about new features")
.on_change(cx.listener(|view, checked, _, cx| {
view.subscribe_newsletter = *checked;
cx.notify();
}))
)
.child(
Switch::new("notifications")
.label("Enable notifications")
.checked(self.enable_notifications)
.on_change(cx.listener(|view, checked, _, cx| {
view.enable_notifications = *checked;
cx.notify();
}))
)
.child(
Switch::new("remember")
.label("Remember me")
.checked(self.remember_me)
.small()
.on_change(cx.listener(|view, checked, _, cx| {
view.remember_me = *checked;
cx.notify();
}))
)#Custom Styling
Switch::new("custom")
.label("Custom styled switch")
.w(px(200.))
.checked(true)
.on_change(|checked, _, _| {
println!("Custom switch: {}", checked);
})#Animation
The switch features smooth animations:
- Toggle animation: 150ms duration when switching states
- Background color transition: Changes from switch color to primary color
- Position animation: Smooth movement of the toggle indicator
- Disabled state: Animations are disabled when the switch is disabled
#API Reference
#Switch
| Method | Description |
|---|---|
new(id) | Create a new switch with the given ID |
checked(bool) | Set the checked/toggled state |
label(text) | Set label text for the switch |
label_side(side) | Position label (Side::Left or Side::Right) |
disabled(bool) | Set disabled state |
tooltip(text) | Add tooltip text |
color(color) | Set background color when checked (default: theme.primary) |
on_change(fn) | Requested checked value, receives &bool |
focus_ring(bool) | Draw the focus ring around the track when focused (default: true) |
tab_stop(bool) | Take part in Tab traversal (default: true) |
tab_index(isize) | Position in the tab order within a tab group (default: 0) |
#Styling
Implements Sizable and Disableable traits:
small()- Small switch size (28x16px toggle area)medium()- Medium switch size (36x20px toggle area, default)with_size(size)- Set explicit sizedisabled(bool)- Disabled state
#Styling Properties
The switch can also be styled using GPUI’s styling methods:
w(width)- Custom widthh(height)- Custom height- Standard margin, padding, and positioning methods
#Switch
An on/off switch. Mirrors GPUI Component's `Switch`: a label, sizes, and a sliding thumb.
| Name | Kind | Type | Default |
|---|---|---|---|
checked | in-out | bool | |
label | in | string | |
enabled | in | bool | true |
size | in | ControlSize | ControlSize.medium |
changed | callback | (checked: bool) |