Components / Selection & input
Text field
Markdown crates/ui/src/input.rs docs.rs
use ui::input::{self, TextField};
input::init(cx); // once, at startup
let field = cx.new(|cx| TextField::new(cx).with_placeholder("Search…"));
// …then render it: .child(field.clone())The one component here that is not a plain function: editing needs state, so a field is an entity the caller holds, the way SwiftUI's TextField binds to @State.
Rebinding
use ui::input::{self, Home, KEY_CONTEXT};
cx.bind_keys([KeyBinding::new("ctrl-a", Home, Some(KEY_CONTEXT))]);init is a convenience. Every action is public and every binding is scoped to the field's key context, so cmd-a never comes to mean "select all" for the whole app. It is all-or-nothing — take the defaults or bind the lot.
API
impl TextField {
pub fn new(cx: &mut Context<Self>) -> Self;
pub fn with_placeholder(self, placeholder: impl Into<SharedString>) -> Self;
/// Default ten. Steps are runs, not keystrokes — a run ends when the caret
/// moves or you switch between typing and deleting.
pub fn with_undo_limit(self, limit: usize) -> Self;
pub fn content(&self) -> &SharedString;
/// Clears the undo history: a programmatic reset is not something the user
/// did, so there is nothing to walk back past.
pub fn set_content(&mut self, content: impl Into<SharedString>, cx: &mut Context<Self>);
pub fn clear(&mut self, cx: &mut Context<Self>);
/// The byte offset the caret sits at.
pub fn cursor(&self) -> usize;
/// Where a byte offset sits on screen — the anchor for a mention picker
/// under the `#` that opened it. `None` until the field has painted once.
pub fn offset_bounds(&self, offset: usize, window: &Window) -> Option<Bounds<Pixels>>;
// ...
}Motion follows the platform: on macOS cmd is line, option is word, plus the emacs chords every native field honours; elsewhere ctrl is word. Word bounds are UAX#29, and arrows step by grapheme so a flag emoji moves as a unit. Platform input ranges are UTF-16 and the field stores bytes.