Skip to content

TextInput

Jeff Day edited this page Aug 22, 2026 · 4 revisions

Wire name textinput · Renders on terminal and graphical

A single-line editable text field. It owns a caret, a selection, an undo-free edit model, clipboard actions with a right-click menu, and input-method composition; it is the trinket a text-entry keystroke is delivered to.

new textinput placeholder="Search…"

Quick example

w=new window title="Find" width=360 height=120 children={
	p=new panel layout=vbox spacing=0 children={
		new label caption="Find what:"
		q=new textinput placeholder="type to search"
		new button caption="Find" default action=find.go
	}
}
query=w.p.q
q := ui.TextInput("query")
q.OnChange(func(s string) { /* every edit, with the new text */ })
q.SetText("initial")

Properties

Set at construction, or later with set.

Property Type Default Meaning
placeholder string Placeholder text shown when empty.
text string Editable content (server-authoritative).

Plus the common properties every trinket carries: enabled visible name min_width min_height max_width max_height column_units row_units font acc_name stretch align fg bg.

A live host answers for itself. conn.Describe() returns the running service's property registry, with types, defaults and tips, which is the authority if this table and your build disagree.

Events

change — The content changed through user editing — a typed character, a deletion, a paste, or a committed composition. A set from the client does not raise it.

Field Type Meaning
trinket uint The field's object ID.
text string The full new content.

change does not fire for a set text=… from the client; only user edits are reported, so a write-through cannot echo back and loop.

Client API

Go

q := ui.TextInput("query")     // handle, subscribed to "change"
q.Text()                       // the client-side replica's text
q.SetText("hello")             // writes through to replica and display
q.OnChange(func(s string) { … })

Python

q = ui.text_input("query")
q.text()
q.set_text("hello")
q.on_change(lambda s: ...)

C

uint64_t q = kt_ui_id(ui, "query");
kt_set(conn, q, "text=\"hello\"");
kt_on(conn, q, "change", on_change, NULL);
/* inside on_change: const char *s = kt_event_text(ev, "text"); */

Each client keeps a replica of the text so Text() is a local read rather than a round trip. SetText updates the replica and sends the property in one call; incoming change events update it before your handler runs.

Keys

Bindings come from the keymap, so a host or application can rebind any of them; these are the defaults. ^X is Control-X, M- is Mega, s- is Super, S- is Shift.

Key Does
Left Right Move the caret; collapse a selection if one is up.
S-Left S-Right Extend the selection by one character.
Home End Caret to start / end.
S-Home S-End Select to start / end.
^A Go to the start — or, when the caret is already there with nothing selected, select all and put the caret at the end.
^E Caret to end.
Backspace, Delete Erase behind the caret, or the selection.
FDel Erase ahead of the caret.
^U Clear the field.
M-a, s-a (macOS) Select all.
^X ^C ^V Cut, copy, paste.
Return Fires the field's activate handler — the "submit" gesture. Does not insert.

^A's second meaning is free: it occupies only the case where the first would do nothing at all. It is there so both habits reach something — someone who types ^A for the start of the line gets it, and someone who types it for select-all finds that too, without either having to know which convention this field follows.

Anything that types a character inserts it, replacing the selection if there is one. Which chords type is the host's answer, not this trinket's: a chord the host watched is settled by what it observed the keyboard produce, including observing that it produced nothing (a dead key arming an accent). Where there is no host to ask — the terminal backend — a one-character key name is the character.

Mouse

Gesture Does
Click Place the caret, take focus.
Shift-click Extend the selection to the click.
Double-click Select the word under the pointer.
Triple-click Select all.
Drag Extend the selection; past either edge it auto-scrolls, and keeps scrolling while the pointer is held still out there, faster the further out it is.
Right-click Context menu: Cut, Copy, Paste, — , Select All.

The multi-click run is 400 ms between clicks; a slower click restarts it.

Behavior

Who owns the text

The display service holds the text and is the authority on it. A client's Text() reads a replica kept in step by change events, so it is current as of the last event delivered — not a synchronous read of the field. Two clients driving the same field see the same content because both are mirroring the same server-side value.

Composition

An input method's in-flight composition is painted at the caret, underlined and in the caret's colour, and is not in text — it enters only when the platform commits it, at which point it arrives as ordinary typed input and raises one change. Dead keys, preedit spans and press-and-hold character palettes all resolve through this path on both surfaces. A read-only or disabled field declines the composition rather than showing it somewhere it could never land.

Caret

The caret blinks, and any keystroke or click makes it immediately visible so it never appears to swallow input during its dark phase. On the terminal surface the field asks the platform for the real hardware caret, so the outer terminal's own cursor sits where the text will go — which is also what a screen reader and an OS input method follow.

Accessibility

Role TextInput, or PasswordInput when the echo mode hides the content. The value is exposed; read-only and disabled are reported as states. Set acc_name where the visible label is not adjacent.

Size

The default size hint is 20 characters wide by one row tall, measured in the field's effective font — so it is 20 characters at any font size, not a fixed pixel box. It is an inline trinket, so a vertical box layout gives it horizontal margins. Constrain it with min_width / max_width or let stretch take the row.

Not yet on the wire

The field does more than the protocol currently exposes. These behaviors are implemented and working; there is no property or verb to reach them by yet, so an application cannot ask for them. They are listed so you know what is coming rather than what is missing.

Behavior Notes
Read-only Shows and selects its content, refuses edits and compositions.
Maximum length A cap on content length; unlimited by default.
Echo mode Normal, password, password-on-edit, or no echo. Password echo also changes the accessibility role.
Caret position Read and set the caret index.
Selection Select all, clear the selection, read the selected text.
Submit handler What Return fires, as something an application can name.
Clipboard actions Cut, copy and paste as commands, as the context menu invokes them.

These are interaction state rather than construction state, which is why they are queued behind the set verb and event slices rather than being added as build-time properties.

See also

Common Properties · Editor — multi-line · ComboBox — a text field with a list · Properties and Values · Events

Clone this wiki locally