Input

Text input field with cursor, placeholder text, and focus states. Focus the input to receive keyboard input.

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)

Construct api

import { Input, createCliRenderer } from "@opentui/core"

const renderer = await createCliRenderer()

const input = Input({
  placeholder: "Enter your name...",
  width: 25,
})

input.focus()
renderer.root.add(input)

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",
})

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 when the input loses focus (blur) or when you press Enter, but only if the value changed since focus:

input.on(InputRenderableEvents.CHANGE, (value: string) => {
  console.log("Value committed:", value)
})

Enter event

Emitted when an Enter/Return submit succeeds. No event is emitted 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.value

Setting 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

import { Box, Text, Input, delegate, createCliRenderer } from "@opentui/core"

const renderer = await createCliRenderer()

function LabeledInput(props: { id: string; label: string; placeholder: string }) {
  return delegate(
    { focus: `${props.id}-input` },
    Box(
      { flexDirection: "row", marginBottom: 1 },
      Text({ content: props.label.padEnd(12), fg: "#888888" }),
      Input({
        id: `${props.id}-input`,
        placeholder: props.placeholder,
        width: 20,
        backgroundColor: "#222",
        focusedBackgroundColor: "#333",
        textColor: "#FFF",
        cursorColor: "#0F0",
      }),
    ),
  )
}

const usernameInput = LabeledInput({
  id: "username",
  label: "Username:",
  placeholder: "Enter username",
})

const passwordInput = LabeledInput({
  id: "password",
  label: "Password:",
  placeholder: "Enter password",
})

const form = Box(
  {
    width: 40,
    borderStyle: "rounded",
    title: "Login",
    padding: 1,
  },
  usernameInput,
  passwordInput,
)

// Focus the username input
usernameInput.focus()

renderer.root.add(form)

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()
  }
})