TextInput

A single-line field for entering and editing free-form text.

Installation

  1. Install the package.
npm install @hashintel/ds-components
  1. Import the component.
import { useState } from "react";

import { TextInput } from "@hashintel/ds-components";

export const EntityTypeNameInput = () => {
  const [name, setName] = useState("");

  return (
    <TextInput
      name="entityTypeName"
      placeholder="e.g. Research paper"
      value={name}
      onChange={setName}
    />
  );
};

When to use

  • Do: Use TextInput for a single line of free-form text: names, titles, emails, URLs, search queries.

When not to use

  • Don't: Don't use TextInput for multi-line text — use TextArea.
  • Don't: Don't use it for numeric values — NumberInput adds min/max, stepping, and rejects non-numeric keys.
  • Don't: Don't collect values from a known set as free text — use Select, or Combobox when the list is long or searchable.

Examples

Basic

TextInput is always controlled — value and onChange are required, and the handler receives the new string first with the raw change event second. null and undefined values render as empty.

Input types

Set type to match the content so devices show the right keyboard and browsers validate natively; for numbers use NumberInput. Autofill and password managers are blocked by default — set autocomplete on fields they should fill, such as sign-in emails and passwords.

Use inputMode when the content is digits but not a number — IDs, one-time codes — to get the numeric keyboard without number-input semantics.

Disabled

disabled greys the field and ignores input. Prefer readonly when the user only needs to see the value — disabled styling has poor contrast and suggests the value might become editable.

Invalid

invalid turns the border red and sets aria-invalid. Pair it with a visible message — Form.Field's errors renders and announces one.

Loading

Set loading while a lookup or save runs — a spinner appears at the end of the field. The input stays editable.

Read-only

readonly strips the field chrome entirely and renders the value as plain text — use it to display stored values alongside editable ones. Unlike disabled, the value reads as content, not as a greyed-out control.

e7f2a49c-3b1d-4e08

Clearable

clearable adds a clear button that appears when the field is hovered or focused and a value is present. The default clear empties the input through the normal change pipeline — onChange fires with "" — and keeps focus in the field.

Edit icon

showEditIcon adds a pencil at the end of the field to signal that a displayed value is editable. The icon hides while the input is focused.

Variants

default draws a bordered field; subtle is borderless and reads as inline text until hovered or focused. Use subtle for click-to-edit values such as titles and table cells.

Sizes

md is the default. Use sm and below in dense chrome such as toolbars and table cells, and lg for prominent page-level fields; give Form.Field the same size so the label scales with the input.

Widths

The presets align stacked inputs without custom CSS; fullWidth — the default — fills the container. fitContent tracks the value's length as the user types.

Prefix and suffix

An adornment is an icon ({ iconName }), text ({ text }), or any node ({ content }); adding onClick to the first two renders it as a button. Set the adornment's variant: "subtle" to drop its background and divider.

https://
kg

Styled value

styledValue renders a formatted view of the value while the input is unfocused; focusing reveals the raw value for editing. Use it to show units, thousands separators or highlighting without corrupting what the user typed.

8,336,817

Connected inputs

Set connectToRightInput on the left input and connectToLeftInput on the right to join a pair into one visual control. Only the default variant connects — subtle and readonly inputs render separately.

In a form field

Form.Field supplies the label, description and errors, and links the label to the input automatically — see the Form docs for layouts, rows and sections.

Shown in search results and the type editor.

Behavior

  • Browser autofill and password managers are suppressed by default — set autocomplete to allow them. Clearable inputs always suppress autofill.

Content

  • Never put requirements in the placeholder — it disappears as the user types. Put format rules in Form.Field's description.
  • Keep prefix/suffix text to short units and symbols: "https://", "kg", "MB".
  • Write error messages as instructions that reuse the label's words: "Enter an entity type name".

Accessibility

TextInput renders a native <input> with standard text-editing behavior.

What TextInput provides

  • Inside a Form.Field the input adopts the field's generated id, so the label is associated automatically; aria-* props pass through to the <input>.

What you must do

  • Always name the input: wrap it in a Form.Field, or pass aria-label where a visible label genuinely can't fit — a placeholder is not a label.
  • Icon adornment buttons ({ iconName, onClick }) carry no accessible name — when the action needs one, pass { content } with your own labelled button.
  • Don't signal errors with invalid color alone — pair it with a message, e.g. Form.Field's errors.

API reference

TextInput

PropTypeDescription
value
string |⁠ null |⁠ undefined
onChange
(value: string, event: ChangeEvent<HTMLInputElement, Element>) => void
onClick
MouseEventHandler<Element>
size
"xxs" |⁠ "xs" |⁠ "sm" |⁠ "md" |⁠ "lg"
default: "md"
placeholder
string
prefix
PrefixOrSuffix
suffix
PrefixOrSuffix
variant
"subtle" |⁠ "default"
default: "default"
type
HTMLInputTypeAttribute
default: "text"
loading
boolean
disabled
boolean
tabIndex
number
autoFocus
boolean |⁠ "never"
onKeyDown
KeyboardEventHandler<Element>
onFocus
FocusEventHandler<HTMLInputElement>
onBlur
FocusEventHandler<HTMLInputElement>
width
"xs" |⁠ "sm" |⁠ "md" |⁠ "lg" |⁠ "fullWidth" |⁠ "fitContent"
default: "fullWidth"
required
boolean
name
string
invalid
boolean
inputMode
"search" |⁠ "text" |⁠ "none" |⁠ "email" |⁠ … 4 more
readonly
boolean
align
"left" |⁠ "right" |⁠ "center"
default: "left"
connectToLeftInput
boolean
connectToRightInput
boolean
styledValue
ReactNode
clearable
boolean |⁠ { onClear: () => void; }
showEditIcon
boolean
autocomplete
boolean
default: false
maxLength
number
minLength
number
pattern
string
spellcheck
boolean

PrefixOrSuffix

The object shape prefix and suffix take.

PropTypeDescription
iconName
"function" |⁠ "filter" |⁠ "at" |⁠ "circle" |⁠ … 137 more
text
string
content
ReactNode
onClick
(() => void) |⁠ (() => void)
disabled
boolean
variant
"subtle" |⁠ "default"
default: "default"

Was this page helpful?

On this page