Input
Input edits one line of text and supplies a cursor, placeholder, and focus styles. Use Textarea for multi-line editing.
Focus the input to receive keyboard input.
Availability#
| Field | Availability |
|---|---|
| Package | @opentui/core |
| Core renderable | InputRenderable |
| React | <input> (automatic) |
| Solid | <input> (automatic) |
| Status | Built in |
Basic usage#
Renderable API#
import { InputRenderable, InputRenderableEvents, createCliRenderer } from "@opentui/core"
const renderer = await createCliRenderer()
const input = new InputRenderable(renderer, {
id: "name-input",
width: 25,
placeholder: "Enter your name...",
})
input.on(InputRenderableEvents.CHANGE, (value) => {
console.log("Input value:", value)
})
input.focus()
renderer.root.add(input)An empty input displays its placeholder:
Focus states#
The input uses its focused colors while it has focus:
const input = new InputRenderable(renderer, {
id: "styled-input",
width: 30,
placeholder: "Type here...",
backgroundColor: "#1a1a1a",
focusedBackgroundColor: "#2a2a2a",
textColor: "#FFFFFF",
cursorColor: "#00FF00",
})After focusing the input and typing a name:
Events#
Input event#
Emitted after these operations:
- Typing, paste, or
insertText()inserts text. - A delete key, a delete method such as
deleteCharBackward(),undo(), orredo()runs. - You assign a different
value.
The listener receives the current value. Other buffer methods, such as setText(), insertChar(), deleteSelection(),
and deleteRange(), do not emit it:
import { InputRenderableEvents } from "@opentui/core"
input.on(InputRenderableEvents.INPUT, (value: string) => {
console.log("Current value:", value)
})Change event#
Emitted on blur, or after a successful submit(), when the value differs from the last commit baseline:
input.on(InputRenderableEvents.CHANGE, (value: string) => {
console.log("Value committed:", value)
})The constructor and each focus() call set the baseline. Each emitted CHANGE event updates it. Thus, blur does not
emit another event if the value did not change after a successful commit.
Enter event#
Emitted when submit() succeeds. Return, keypad Enter, and linefeed call submit(). If the current UTF-16 code-unit length
is less than minLength, submit() fails and the input emits no event:
input.on(InputRenderableEvents.ENTER, (value: string) => {
console.log("Submitted value:", value)
})Getting the current value#
const currentValue = input.valueSetting the value#
input.value = "New value"Properties#
| Property | Type | Default | Description |
|---|---|---|---|
width |
number, "auto", or percentage string |
"auto" |
Input field width |
value |
string |
"" |
Initial text, with newlines removed |
placeholder |
string |
"" |
Placeholder text when empty |
minLength |
number |
0 |
Minimum UTF-16 code-unit length required for submit |
maxLength |
number |
1000 |
Maximum UTF-16 code-unit length |
backgroundColor |
string | RGBA |
"transparent" |
Background when unfocused |
focusedBackgroundColor |
string | RGBA |
backgroundColor, else "transparent" |
Background when focused |
textColor |
string | RGBA |
"#FFFFFF" |
Text color |
cursorColor |
string | RGBA |
"#FFFFFF" |
Cursor color |
position |
"relative" | "absolute" |
"relative" |
Positioning mode |
Example: login form#
Input has no password-masking mode. This example shows the password value as normal terminal text. Do not use this
pattern for real secrets.
import { BoxRenderable, InputRenderable, TextRenderable, createCliRenderer } from "@opentui/core"
const renderer = await createCliRenderer()
const form = new BoxRenderable(renderer, {
width: 40,
borderStyle: "rounded",
title: "Login",
padding: 1,
gap: 1,
})
const usernameInput = new InputRenderable(renderer, {
id: "username-input",
placeholder: "Enter username",
width: 20,
backgroundColor: "#222",
focusedBackgroundColor: "#333",
})
const passwordInput = new InputRenderable(renderer, {
id: "password-input",
placeholder: "Enter password",
width: 20,
backgroundColor: "#222",
focusedBackgroundColor: "#333",
})
form.add(new TextRenderable(renderer, { content: "Username:", fg: "#888888" }))
form.add(usernameInput)
form.add(new TextRenderable(renderer, { content: "Password:", fg: "#888888" }))
form.add(passwordInput)
renderer.root.add(form)
usernameInput.focus()Tab navigation#
Add tab navigation between inputs:
const inputs = [usernameInput, passwordInput]
let focusIndex = 0
renderer.keyInput.on("keypress", (key) => {
if (key.name === "tab") {
focusIndex = (focusIndex + 1) % inputs.length
inputs[focusIndex].focus()
}
})Related concepts#
Read Interaction, focus, and selection for focus and event behavior. Read Text and terminal cells before enforcing limits that depend on code points, graphemes, or display cells.