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 changes appearance when focused:
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 text insertion and deletion operations, and when assigning a different value. The listener receives the current value:
import { InputRenderableEvents } from "@opentui/core"
input.on(InputRenderableEvents.INPUT, (value: string) => {
console.log("Current value:", value)
})Change event#
Fires 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)
})Each focus() call sets 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 an Enter/Return submit succeeds. The input emits no event when the current UTF-16 code-unit length is less
than minLength:
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 value |
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" |
Effective positioning mode |
Example: login form#
Input has no password-masking mode. This demonstration displays 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.