Input
A single-line text input with validation, masking, prefix/suffix elements, and different visual states. Use Textarea for ordinary multi-line text and Editor for source code.
#Import
use gpui_kit::component::input::{Input, InputState};
#Usage
#Basic Input
let input = cx.new(|cx| InputState::new(window, cx));
Input::new(&input)
#With Placeholder
let input = cx.new(|cx|
InputState::new(window, cx)
.placeholder("Enter your name...")
);
Input::new(&input)
#With Default Value
let input = cx.new(|cx|
InputState::new(window, cx)
.default_value("John Doe")
);
Input::new(&input)
#Cleanable Input
Input::new(&input)
.cleanable(true) // Show clear button when input has value
#With Prefix and Suffix
use gpui_kit::component::{Icon, IconName};
// With prefix icon
Input::new(&input)
.prefix(Icon::new(IconName::Search).small())
// With suffix button
Input::new(&input)
.suffix(
Button::new("info")
.ghost()
.icon(IconName::Info)
.xsmall()
)
// With both
Input::new(&input)
.prefix(Icon::new(IconName::Search).small())
.suffix(Button::new("btn").ghost().icon(IconName::Info).xsmall())
#Password Input (Masked)
let input = cx.new(|cx|
InputState::new(window, cx)
.masked(true)
.default_value("password123")
);
Input::new(&input)
.content_type(InputContentType::Password)
.mask_toggle() // Shows toggle button to reveal password
While the value is masked, the input keeps it out of the clipboard and out of
the selection: Copy and Cut do nothing (and are disabled in the context menu),
a word-wise delete takes everything before the caret, and a double click
selects the whole value instead of one word. Paste and Select All keep working,
and revealing the value with mask_toggle restores all of them.
#Input Sizes
Input::new(&input).large()
Input::new(&input) // medium (default)
Input::new(&input).small()
#Disabled Input
Input::new(&input).disabled(true)
#Read-only Input
Unlike disabled, a read-only input keeps the normal appearance and still can
be focused, selected and copied, it only rejects the changes made by the user.
Input::new(&input).readonly(true)
#Clean on ESC
let input = cx.new(|cx|
InputState::new(window, cx)
.clean_on_escape() // Clear input when ESC is pressed
);
Input::new(&input)
#Input Validation
// Validate float numbers
let input = cx.new(|cx|
InputState::new(window, cx)
.validate(|s, _| s.parse::<f32>().is_ok())
);
// Regex pattern validation
let input = cx.new(|cx|
InputState::new(window, cx)
.pattern(regex::Regex::new(r"^[a-zA-Z0-9]*$").unwrap())
);
#Input Masking
// Phone number mask
let input = cx.new(|cx|
InputState::new(window, cx)
.mask_pattern("(999)-999-9999")
);
// Custom pattern: AAA-###-AAA (A=letter, #=digit, 9=digit optional)
let input = cx.new(|cx|
InputState::new(window, cx)
.mask_pattern("AAA-###-AAA")
);
// Number with thousands separator
use gpui_kit::component::input::MaskPattern;
let input = cx.new(|cx|
InputState::new(window, cx)
.mask_pattern(MaskPattern::Number {
separator: Some(','),
fraction: Some(3),
})
);
#Handle Input Events
let input = cx.new(|cx| InputState::new(window, cx));
cx.subscribe_in(&input, window, |view, state, event, window, cx| {
match event {
InputEvent::Change => {
let text = state.read(cx).value();
println!("Input changed: {}", text);
}
InputEvent::PressEnter { secondary } => {
println!("Enter pressed, secondary: {}", secondary);
}
InputEvent::Focus => println!("Input focused"),
InputEvent::Blur => println!("Input blurred"),
}
});
#Custom Appearance
// Without default styling
Input::new(&input).appearance(false)
// Use in custom container
div()
.border_b_2()
.px_6()
.py_3()
.border_color(cx.theme().border)
.bg(cx.theme().secondary)
.child(Input::new(&input).appearance(false))
#Context Menu
// The built-in context menu can be disabled.
let input = cx.new(|cx| InputState::new(window, cx).context_menu(false));
// Or you can define a custom context menu.
Input::new(&input).context_menu(|menu, window, cx| {
// You can define your own actions and even utilize
// built-in actions (cut, copy, paste, etc.)
// to avoid having to re-implement that functionality.
menu.menu("Custom Action", Box::new(CustomAction))
.separator()
.menu("Cut", Box::new(input::Cut))
.menu("Copy", Box::new(input::Copy))
.menu("Paste", Box::new(input::Paste))
})
#Examples
#Search Input
let search = cx.new(|cx|
InputState::new(window, cx)
.placeholder("Search...")
);
Input::new(&search)
.prefix(Icon::new(IconName::Search).small())
#Currency Input
let amount = cx.new(|cx|
InputState::new(window, cx)
.mask_pattern(MaskPattern::Number {
separator: Some(','),
fraction: Some(2),
})
);
div()
.child(Input::new(&amount))
.child(format!("Value: {}", amount.read(cx).value()))
#Form with Multiple Inputs
struct FormView {
name_input: Entity<InputState>,
email_input: Entity<InputState>,
}
v_flex()
.gap_3()
.child(Input::new(&self.name_input))
.child(Input::new(&self.email_input))