Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/Augani/kael/llms.txt

Use this file to discover all available pages before exploring further.

Every form control in Kael is a controlled element: you own the value in your view’s state, pass it in each frame, and receive the next value through an on_change callback. This mirrors React’s controlled-component model. All built-in controls also integrate with Kael’s window-scoped undo/redo manager — users get Cmd-Z / Cmd-Shift-Z for free without any extra wiring on your part.

text_input()

A fully featured single-line or multiline editable text field with platform IME support, clipboard integration, and word-boundary navigation.

Signature

pub fn text_input(id: impl Into<ElementId>, text: impl Into<SharedString>) -> TextInput
id must be stable across frames. text is the current field value (you own it).

Methods on TextInput

// Placeholder text displayed when the field is empty
pub fn placeholder(self, placeholder: impl Into<SharedString>) -> Self

// Enable wrapped multiline editing
pub fn multi_line(self) -> Self

// Limit visible height of a multiline field to N lines
pub fn max_lines(self, max_lines: usize) -> Self

// Mask the displayed content (password field)
pub fn password(self) -> Self

// Apply a custom InputMask to normalize edits before they are committed
pub fn mask(self, mask: impl InputMask) -> Self

// Called on every content change with (new_value, window, cx)
pub fn on_change(
    self,
    listener: impl Fn(SharedString, &mut Window, &mut App) + 'static,
) -> Self

// Called when the user presses Enter (single-line) or Cmd-Enter (multiline)
pub fn on_submit(
    self,
    listener: impl Fn(SharedString, &mut Window, &mut App) + 'static,
) -> Self

// Replace the entire paint surface with a custom renderer
pub fn render_with(
    self,
    renderer: impl Fn(TextInputRenderState, &mut Window, &mut App) + 'static,
) -> Self

TextInputRenderState (for custom renderers)

When you supply .render_with(), Kael calls your closure each frame with a TextInputRenderState snapshot:
FieldTypeDescription
valueSharedStringThe underlying field value
display_textSharedStringText as displayed (masked or placeholder)
placeholderOption<SharedString>The configured placeholder
showing_placeholderboolTrue when placeholder is visible
focusedboolWhether the field owns keyboard focus
hoveredboolWhether the pointer hovers the hitbox
multi_lineboolWhether multiline mode is active
linesVec<TextInputRenderLine>Shaped lines and their paint origins
selection_boundsVec<Bounds<Pixels>>Selection rectangles in render space
cursor_boundsOption<Bounds<Pixels>>Caret rectangle, when visible
The snapshot also provides three convenience paint methods:
state.paint_text(window, cx);
state.paint_selection(color, window);
state.paint_cursor(color, window);
state.paint_default_contents(window, cx); // all three with default colors

Keyboard actions

The following actions are bound inside the TextInput key context automatically: Backspace, Delete, DeleteWordBackward, DeleteWordForward, MoveLeft, MoveRight, MoveWordLeft, MoveWordRight, SelectLeft, SelectRight, SelectWordLeft, SelectWordRight, MoveToStart, MoveToEnd, SelectToStart, SelectToEnd, SelectAll, Paste, Copy, Cut, Undo, Redo, InsertNewline, Submit

Example

text_input("search-field", self.query.clone())
    .placeholder("Search…")
    .on_change(|value, _window, cx| {
        cx.update_view(self_entity, |view, _cx| {
            view.query = value;
        });
    })
    .on_submit(|value, _window, cx| {
        cx.dispatch_action(SearchAction { query: value });
    })
    .w_full()
    .px(px(12.0))
    .py(px(8.0))
    .bg(theme.input_bg)
    .rounded_md()

checkbox()

A controlled tri-state checkbox with built-in indeterminate support.

Signature

pub fn checkbox(id: impl Into<ElementId>, checked: bool) -> Checkbox

Methods on Checkbox

// Visible label rendered next to the indicator
pub fn label(self, label: impl Into<SharedString>) -> Self

// Put the checkbox into an indeterminate visual state
pub fn indeterminate(self, indeterminate: bool) -> Self

// Disable the checkbox, preventing user interaction
pub fn disabled(self) -> Self

// Called with the next checked value after user interaction
pub fn on_change(
    self,
    listener: impl Fn(&bool, &mut Window, &mut App) + 'static,
) -> Self

// Replace the default indicator + label with a custom element
pub fn render_with(
    self,
    renderer: impl Fn(CheckboxRenderState, &Window, &App) -> AnyElement + 'static,
) -> Self
CheckboxRenderState exposes checked, indeterminate, label, focused, and disabled.

Example

checkbox("notifications-enabled", self.notifications_enabled)
    .label("Enable notifications")
    .on_change(|&checked, _window, cx| {
        cx.update_view(self_entity, |view, _| {
            view.notifications_enabled = checked;
        });
    })
When the checkbox is in the indeterminate state, the first click always transitions it to checked: true, regardless of the previous checked value.

toggle()

A binary on/off toggle switch — semantically equivalent to a checkbox but rendered as a sliding pill.

Signature

pub fn toggle(id: impl Into<ElementId>, on: bool) -> Toggle

Methods on Toggle

// Visible label
pub fn label(self, label: impl Into<SharedString>) -> Self

// Disable the toggle
pub fn disabled(self) -> Self

// Called with the next on/off state
pub fn on_change(
    self,
    listener: impl Fn(&bool, &mut Window, &mut App) + 'static,
) -> Self

// Replace the default pill with a custom element
pub fn render_with(
    self,
    renderer: impl Fn(ToggleRenderState, &Window, &App) -> AnyElement + 'static,
) -> Self
ToggleRenderState exposes on, label, focused, and disabled.

Example

toggle("dark-mode", self.dark_mode)
    .label("Dark mode")
    .on_change(|&on, _window, cx| {
        cx.update_view(self_entity, |view, _| view.dark_mode = on);
    })

slider()

A continuous or discrete range input rendered as a draggable track.

Signature

pub fn slider(id: impl Into<ElementId>, value: f64) -> Slider

Methods on Slider

// Set the minimum value (default: 0.0)
pub fn min(self, min: f64) -> Self

// Set the maximum value (default: 100.0)
pub fn max(self, max: f64) -> Self

// Set the keyboard step increment and drag snap interval
pub fn step(self, step: f64) -> Self

// Snap drag interactions to discrete step boundaries
pub fn discrete(self) -> Self

// Render the slider vertically (default size becomes 24 × 160 px)
pub fn vertical(self) -> Self

// Disable the slider
pub fn disabled(self) -> Self

// Called continuously during drag and on keyboard input
pub fn on_change(
    self,
    listener: impl Fn(&f64, &mut Window, &mut App) + 'static,
) -> Self

// Replace the default track + thumb with a custom renderer
pub fn render_with(
    self,
    renderer: impl Fn(SliderRenderState, Bounds<Pixels>, &mut Window, &mut App) + 'static,
) -> Self
SliderRenderState exposes value, min, max, percentage (0.0–1.0), dragging, focused, and disabled. The undo entry is recorded once per drag gesture (on mouse up), not on every intermediate movement.

Example

slider("volume", self.volume)
    .min(0.0)
    .max(1.0)
    .step(0.01)
    .on_change(|&value, _window, cx| {
        cx.update_view(self_entity, |view, _| view.volume = value);
    })
    .w_full()

select()

A popup-backed combo box for selecting a single value from a labeled option list.

Signature

pub fn select<T, I, O>(id: impl Into<ElementId>, value: T, options: I) -> Select<T>
where
    T: Clone + PartialEq + 'static,
    I: IntoIterator<Item = O>,
    O: Into<SelectOption<T>>
Options can be supplied as SelectOption<T> values or as (T, label) tuples (both implement Into<SelectOption<T>>).

Methods on Select<T>

// Placeholder text shown when no option matches the current value
pub fn placeholder(self, placeholder: impl Into<SharedString>) -> Self

// Enable text filtering inside the popup
pub fn searchable(self) -> Self

// Called with the newly selected value
pub fn on_change(
    self,
    listener: impl Fn(&T, &mut Window, &mut App) + 'static,
) -> Self

// Replace the trigger element with a custom renderer
pub fn render_with(
    self,
    renderer: impl Fn(SelectRenderState, &Window, &App) -> AnyElement + 'static,
) -> Self

// Replace individual option rows with a custom renderer
pub fn render_options_with(
    self,
    renderer: impl Fn(SelectOptionRenderState<T>, &Window, &App) -> AnyElement + 'static,
) -> Self

// Replace the popup shell with a custom renderer
pub fn render_popup_with(
    self,
    renderer: impl Fn(SelectPopupRenderState, Vec<AnyElement>, &Window, &App) -> AnyElement + 'static,
) -> Self

// Replace the in-popup search field with a custom renderer
pub fn render_search_with(
    self,
    renderer: impl Fn(SelectSearchRenderState, AnyElement, &Window, &App) -> AnyElement + 'static,
) -> Self

Example

#[derive(Clone, PartialEq)]
enum Language { Rust, TypeScript, Python }

select(
    "language-select",
    self.language.clone(),
    [
        (Language::Rust,       "Rust"),
        (Language::TypeScript, "TypeScript"),
        (Language::Python,     "Python"),
    ],
)
.placeholder("Choose a language")
.searchable()
.on_change(|lang, _window, cx| {
    cx.update_view(self_entity, |view, _| view.language = lang.clone());
})
.min_w(px(200.0))
All form controls support Styled because they render via div() internally. Chain layout methods (.w_full(), .mt_2(), etc.) directly on the control builder.

Build docs developers (and LLMs) love