Skip to main content

Input

A text input. Input.Search adds a clear button and a search action; Input.TextArea is the multi-line variant. Input.Number handles exact numeric values with step controls.

import { Input } from '@jbpark/ui-kit';

<Input placeholder="Basic input" />
<Input.Search placeholder="Search..." onSearch={value => console.log(value)} />
<Input.TextArea placeholder="Text area" rows={3} />;
<Input.Number
label="Quantity"
min={0}
max={10}
defaultValue={2}
onChange={value => console.log(value)}
/>;
Last search: none

Input​

A thin wrapper with no props beyond React.ComponentPropsWithRef<'input'>.

PropTypeDefault
allowClearbooleantrue
onChange(e: ChangeEvent<HTMLInputElement> | { target: { value: string } }) => void-
onSearch(value: string) => void-

onSearch fires on pressing Enter or clicking the search button. Also accepts the rest of React.ComponentPropsWithRef<'input'>.

Input.TextArea​

A thin wrapper with no props beyond React.ComponentPropsWithRef<'textarea'>.

Input.Number​

Input.Number uses Base UI Number Field for numeric parsing, keyboard steps, validation, and form integration. Supply a visible label, an aria-label, or an external <label htmlFor> paired with id.

PropTypeDefault
labelstring-
valuenumber | null-
defaultValuenumber-
onChange(value, eventDetails) => void-
min / maxnumber-
stepnumber | 'any'1
size'small' | 'middle' | 'large'Config.componentSize or 'middle'
placeholderstring-
disabledbooleanfalse
readOnlybooleanfalse
namestring-
requiredbooleanfalse
classNamestring-
classNames{ label?, group?, input?, decrement?, increment? }-

The callback receives null when the field is cleared. By default, direct typing is clamped to min/max on blur while step buttons and keyboard interactions clamp immediately. Use allowOutOfRange if form validation should report an out-of-range typed value. step="any" disables step validation while the buttons and arrows still step by 1. The component also passes through the remaining Base UI Number Field root props, including format, locale, and onValueCommitted.

Input.OTP​

Segmented verification-code entry built on Base UI OTP Field. Values remain strings, preserving leading zeroes. Provide label, aria-label, or an external label paired with id. Each subsequent slot has its own accessible name; getSlotLabel(index, length) can localize it. aria-describedby describes the group once, rather than repeating the hint on every slot.

<Input.OTP
length={6}
label="Verification code"
name="code"
onChange={value => console.log(value)}
onComplete={value => console.log('Complete:', value)}
/>
PropTypeDefault
lengthpositive safe integer6
value / defaultValuestring-
onChange / onComplete(value, eventDetails) => void-
labelstring-
size'small' | 'middle' | 'large'Config size
validationType'numeric' | 'alphanumeric' | 'none''numeric'
mask, disabled, readOnly, requiredbooleanfalse
name, form, inputMode, autoCompletenative input settingsautocomplete: 'one-time-code'
inputRefRef<HTMLInputElement>first slot
refRef<HTMLDivElement>Base UI group
placeholderstring-
classNames{ label?, group?, input? }-

Numeric mode filters non-digits; alphanumeric mode accepts ASCII letters and numbers. Whitespace is removed, values are clamped to length, and normalizeValue can apply an idempotent transformation. Full paste replaces the code, partial paste starts at the focused slot. Typing advances focus; arrow keys navigate and Backspace removes characters. Base UI handles native editing, autofill and validation.

Omitted or invalid lengths use six slots. Invalid lengths produce a development warning instead of throwing during render. className, style, ref, data attributes and event handlers all apply to the Base UI group root.

onComplete follows onChange when user entry completes the code. Pasting a full code again can fire completion even if the value is unchanged. Initial or externally controlled complete values do not represent user completion. Completion never submits the form or sends/verifies a code. A named hidden input supplies the full string to native forms. SMS delivery and retry timers belong to the application.

Form errors, reset, and focus​

Wrap Input.OTP in Form.Field to display a caller-supplied error. Omit the OTP's label when the field supplies it. The field's invalid state applies to every editable slot; clearing the error also clears that state.

<Form.Field
name="code"
label="Verification code"
error="This code has expired. Request a new code."
>
<Input.OTP name="code" />
</Form.Field>

Base UI OTP Field does not reset its uncontrolled value on native form reset. Use a controlled value and restore it in the form's onReset handler. inputRef points to the first editable slot, so a button can return focus to code entry.

function VerificationForm() {
const [code, setCode] = useState('');
const inputRef = useRef<HTMLInputElement>(null);

return (
<form onReset={() => setCode('')}>
<Input.OTP
label="Verification code"
name="code"
value={code}
onChange={setCode}
inputRef={inputRef}
/>
<Button htmlType="reset">Reset</Button>
<Button onClick={() => inputRef.current?.focus()}>
Focus first slot
</Button>
</form>
);
}

Import useRef and useState from React and Button, Form, and Input from @jbpark/ui-kit for these examples. Reset and focus actions do not complete, submit, or verify a code.