Buttons and inputs
Add friendly controls, cards, badges, icons, and a real text field to the same small app.
Outcome: a compact task card with an editable title, a status badge, a real icon, and a button ready for the actions chapter.
01
Build one useful card
We will keep one focused surface and add only the controls that make its purpose obvious.
Card::elevated()TextInput::new().bind(state)Button::with_label(...)Badge::dot(...)Icon::new(IconId::Plus)02
Six visual controls
Card
Card::elevated creates a themed surface with built-in padding, border, radius, and shadow.
TextInput
TextInput must be bound to writable State before it becomes a view. User edits update that state.
Button
Button::with_label builds a primary themed button. It stays visual here, then the actions chapter connects it to application behavior.
Badge
Badge::dot adds a leading semantic dot. Tone and variant regenerate its style from the default theme.
Icon
Icon::new uses the public IconId catalogue. size and tint adjust its logical extent and color.
Switch
Switch::bind connects a State<bool> in both directions: the control reads the value and writes it when toggled.
Bound or controlled?
Use bind when a control may write to State directly. Use a displayed value plus on_change when a typed action and the central update function should remain in charge. TextInput always needs a writable binding before it becomes a view.
03
Assemble the controls
Add controls in three focused fragments. The field owns editable data, while the status row stays visual until the actions chapter.
Build it in small steps
Each code block changes one idea from the verified reference application.
Step 1: create the editable value
State<String> is the shared value that the field reads and updates.
let task_title = State::new("Publish the tiny app".to_owned());Step 2: bind one text field
bind is required before TextInput becomes a view. User edits are written to the State first.
TextInput::new()
.bind(task_title.clone())
.placeholder("What shall we build?")
.width(420.0),Step 3: add status and a button
Badge carries semantic status. Button uses its themed label style, but has no action yet.
Row::new()
.gap(12.0)
.child(
Badge::dot("Ready")
.tone(BadgeTone::Success),
)
.child(Button::<()>::with_label("Add task")),Checked with Rust 1.88. The input binding, card, button, badge, and icon all come from the public prelude.
Visual first, actions next
The button is intentionally not wired yet. Chapter 7 introduces application actions and immediate feedback one small step at a time.
Try it yourself
Exercise: give the card a status
Build a compact control card where every widget has one obvious role.
- 1Add a TextInput bound to a title and a Badge with the Info tone.
- 2Add a secondary Button and a Switch bound to a State<bool>. The button may stay visual for now.
Use TextInput::bind and Switch::bind for direct two-way bindings. Use with_label_variant for the secondary button.
Typing changes the field, the switch visibly toggles, and all four controls remain readable in a narrower window.