---
title: Input
url: "https://native-sdk.dev/docs/components/input"
docs_index: /llms.txt
lastUpdated: 2026-10-16
---

> For an index of all documentation, see [/llms.txt](/llms.txt).

Use `input` or `text-field` for single-line text entry. Both support model-bound `text` and `placeholder`, `on-input` for edit events, and `on-submit` for Enter. Edit payloads use `TextInputEvent` from `@native-sdk/core/text` in a TypeScript core or `canvas.TextInputEvent` in a Zig core. Use `search-field` for the same editing behavior with search styling.

## Markup

```html
<column gap="12" width="280">
  <input placeholder="Email address" text="{email}" on-input="email_edited" on-submit="subscribe" />
  <text-field placeholder="Project name" text="{project_name}" on-input="name_edited" />
  <input placeholder="Disabled" disabled="true" />
</column>
```

Keep the text in the model and apply each edit in `update`. See [Messages](/docs/native-ui#messages) for the reducer contract:

```ts
import { type TextInputEvent } from "@native-sdk/core/text";
// the same module ships the full byte-splice reducer (applyTextInputEvent)
// for update to fold each edit over the model's draft bytes

export type Msg =
  | { readonly kind: "subscribe" }
  | { readonly kind: "email_edited"; readonly edit: TextInputEvent };
```

```zig
email_buffer: canvas.TextBuffer(128) = .{},
pub fn email(model: *const Model) []const u8 {
    return model.email_buffer.text();
}
// in update:
.email_edited => |edit| model.email_buffer.apply(edit),
```

## Editing keys

The built-in editor follows the platform keymap in `input`, `text-field`, `search-field`, and `combobox`: Backspace/Delete remove one caret unit, Option+Backspace/Delete on macOS (Ctrl+Backspace/Delete elsewhere) remove one word, and Command+Backspace on macOS (with or without Shift) deletes from the caret to the beginning of the field. A non-empty selection always wins and is deleted by itself. The semantic edit still arrives through `on-input`, so `applyTextInputEvent` and `TextBuffer` keep controlled fields synchronized and one undo restores the whole deletion.

## Search field

`search-field` uses the same bindings as `input`. Pair it with a model-filtered list. When it contains text, it displays a clear button. Pressing that button or Escape while focused dispatches a clear edit through `on-input`. For a suggestions menu, see [combobox](/docs/components/combobox).

```html
<search-field width="280" placeholder="Search notes" text="{query}" on-input="query_edited" />
```

## Programmatic construction (Zig)

In a Zig view, the `canvas.Ui` builder constructs the same tree programmatically. `on_input` takes a comptime message constructor: `Ui.inputMsg(.tag)` builds `Msg{ .tag = edit }` for each `canvas.TextInputEvent`.

```zig
ui.column(.{ .gap = 12, .width = 280 }, .{
    ui.el(.input, .{
        .placeholder = "Email address",
        .text = model.email,
        .on_input = Ui.inputMsg(.email_edited),
        .on_submit = .subscribe,
    }, .{}),
    ui.textField(.{ .placeholder = "Project name", .text = model.project_name, .on_input = Ui.inputMsg(.name_edited) }),
    ui.el(.input, .{ .placeholder = "Disabled", .disabled = true }, .{}),
})
```

The search field builds the same way:

```zig
ui.el(.search_field, .{
    .width = 280,
    .placeholder = "Search notes",
    .text = model.query,
    .on_input = Ui.inputMsg(.query_edited),
}, .{})
```

## Attributes

| Attribute     | Description                                                                                                                                                                                                                  |
| ------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `text`        | Text value for text-bearing elements; a literal or one \{binding}.                                                                                                                                                           |
| `placeholder` | Hint text shown while a text entry is empty.                                                                                                                                                                                 |
| `value`       | Value for slider/progress/text entry; a literal or one \{binding}.                                                                                                                                                           |
| `disabled`    | Disables the control; true/false or a \{binding}.                                                                                                                                                                            |
| `autofocus`   | Focusable controls only: moves keyboard focus to the element when it mounts or when the value turns on (edge-triggered - holding it true never re-steals focus). The TEA way to focus an editor on create.                   |
| `on-input`    | Names a Msg variant with canvas.TextInputEvent payload; delivers each text edit.                                                                                                                                             |
| `on-submit`   | Dispatch a Msg on submit: tag or tag:\{payload}. Enter in a text field, primary+enter in a textarea; on a list-item, plain Enter dispatches it as the row's primary action while Space keeps the row's select (on-press).    |
| `on-change`   | Dispatch a Msg on change: tag or tag:\{payload}. Hit-target elements only. On a treeitem, Up/Down/Left/Right/Home/End focus movement prefers on-change over on-press, separating keyboard selection from pointer activation. |

---

For a semantic overview of all documentation, see [/sitemap.md](/sitemap.md)

For an index of all available documentation, see [/llms.txt](/llms.txt)

For agent-facing discovery, including API and MCP surfaces, see [/agents.md](/agents.md)