|Kit

Input

The styled input shell the whole form family renders into — bordered box, focus ring, slots, and invalid / disabled states. Label, description, and error live in TextInput or Field.

Input is the lowest layer of the form family — the shell that Select, Combobox, Autocomplete, and PillsInput all render into. It draws the box, the focus-within ring, the slots, and the invalid / disabled states, and nothing else. Labels, descriptions, and errors are the job of Field, so an Input stays composable.

Looking for a labelled text field?

Use TextInput — it's this component with label / description / error / required built in, like every other control in the family. Input is for composing the shell yourself: inside a Field you already control, or for a field with no visible label of its own.

import { Input, InputBase } from '@42-central/ui-react/input';

<Input placeholder="login@student.42.fr" />

Two pieces ship from the module:

  • Input — a real <input> wrapped in the shell. Native input props (value, onChange, name, type, ref, …) forward straight through.
  • InputBase — the bare shell around an arbitrary control child. It's how the rest of the family mounts a <button> trigger or a <div> of pills inside the same box. Style your control with the exported inputControlClasses.

Playground

Component

Loading preview

Props

Code

<Component size="md" placeholder="login@student.42.fr" />

Variants

Two shells. default is bordered; unstyled strips the chrome but keeps the layout (height + slots) for full-custom inputs.

Code

<Input variant="default" placeholder="Default" />
<Input variant="unstyled" placeholder="Unstyled" />

Sizes

Five heights — xs through xl. The control font, padding, and any slot icons scale to match.

Code

<Input size="xs" placeholder="xs" />
<Input size="sm" placeholder="sm" />
<Input size="md" placeholder="md" />
<Input size="lg" placeholder="lg" />
<Input size="xl" placeholder="xl" />

Slots

startSlot and endSlot are RTL-aware (start = left in LTR, right in RTL). Icons placed in them are auto-sized to the input's size.

Both slots are decorative: their wrapper spans are aria-hidden, so an interactive control placed in one is invisible to assistive tech. Mount a real button — a clear button, a reveal toggle — as a direct child of InputBase instead, the way PasswordInput mounts its own.

Code

<Input startSlot={<Search />} placeholder="Search" />
<Input startSlot={<Mail />} endSlot={<CircleX />} placeholder="login@student.42.fr" />

States

invalid swaps the border and focus ring to red (and sets aria-invalid). disabled dims the shell and blocks input; readOnly keeps full contrast and stays focusable but rejects edits.

Code

<Input invalid defaultValue="not-an-email" />
<Input disabled defaultValue="Locked" />
<Input readOnly defaultValue="Read-only" />

InputBase — custom controls

InputBase renders the shell around any control child. This is how a Select trigger (a <button>) or a PillsInput (a <div>) get the exact same box. Apply inputControlClasses to your control so it inherits the shell's font and fills the row.

import { InputBase, inputControlClasses } from '@42-central/ui-react/input';

<InputBase pointer endSlot={<ChevronDown />}>
  <button type="button" className={inputControlClasses}>
    {value ?? <span className="text-gray-light-500">Pick a value</span>}
  </button>
</InputBase>

API

Prop

Type

Input forwards every other prop to the underlying <input> (value, defaultValue, onChange, name, type, placeholder, ref, …). className styles the shell root. InputBase takes the same shell props and renders its children as the control.

Accessibility

  • Input is an unlabeled control by design. Pair it with Field (or your own <label htmlFor>) to give it an accessible name, description, and error text — Field wires the aria-* relationships for you.
  • invalid sets aria-invalid on the input so assistive tech announces the error state.
  • The focus ring is focus-within, so it appears whenever the nested control is focused — including the <button> / <div> controls mounted via InputBase.
  • RTL: the shell is a plain flex row, so startSlot / endSlot and padding flip automatically under dir="rtl".

Changelog

v0.18.0
  • asChild is a compile error on CircularProgress, Progress, Rating, Slider, Divider, Field, InputBase and PillsInput

    #294
v0.10.0
  • Declare the ref prop the docs already promised

    #145
v0.6.0
  • Inputs drop the filled variant and the color prop

    #96
v0.5.0
  • Wire the field's description and error to the control with aria-describedby and aria-errormessage

    #57
v0.3.1
  • The input shell's translucent fill gets a matching translucent border

    #37
v0.3.0
  • Show the focus ring on shells that are themselves focusable: TreeSelect, TreeMultiSelect and PinInput

    #35
v0.0.1
  • Input, Field, PillsInput and Pill: the shared input shell, label/help/error wrapper and chips

On this page