Forms
TextInput
Pill text field with label, required marker, error message and uppercase mode.
npx bezel-add add text-inputAbout
A controlled React text input with a rounded pill shape, a linked label and inline validation text. Use it in forms where you want the label, required asterisk and error message handled in one component. It can force uppercase as the user types (useful for codes and IDs), switches to a red border when an error is set, and supports text, number and email types.
Key props: onChange (receives the new string value, already uppercased if requested), error (message shown under the field and turns the border red), mandatory (adds a required asterisk to the label), uppercase (converts input to capitals as you type)
packages/ui/src/forms/TextInput.tsx · 62 lines
import React from 'react';
type TextInputProps = {
name: string;
label: string;
value: string;
onChange: (value: string) => void;
placeholder?: string;
error?: string;
disabled?: boolean;
type?: 'text' | 'number' | 'email';
mandatory?: boolean;
uppercase?: boolean;
maxLength?: number;
};
export function TextInput({
name,
label,
value,
onChange,
placeholder,
error,
disabled,
type = 'text',
mandatory,
uppercase,
maxLength,
}: TextInputProps) {
const handleChange = (e: React.ChangeEvent<HTMLInputElement>) => {
const v = e.target.value;
onChange(uppercase ? v.toUpperCase() : v);
};
return (
<div className="flex flex-col gap-1">
<label htmlFor={name} className="text-sm font-medium text-neutral-700">
{label}
{mandatory && <span className="text-[color:var(--bz-danger,#b91c1c)] ml-1">*</span>}
</label>
<input
id={name}
name={name}
type={type}
value={value}
onChange={handleChange}
placeholder={placeholder}
disabled={disabled}
maxLength={maxLength}
className={[
'h-11 px-4 rounded-full border bg-white text-neutral-900 placeholder:text-[color:var(--bz-ink-subtle,#6b6b70)]',
'focus:outline-none focus:ring-2 focus:ring-indigo-500 transition-[border-color,box-shadow] duration-200',
uppercase ? 'uppercase' : '',
error ? 'border-red-500 focus:border-red-500' : 'border-[color:var(--bz-line-control,#8a8a8e)]',
disabled ? 'bg-neutral-100 text-neutral-500 cursor-not-allowed' : '',
].join(' ')}
autoComplete="off"
/>
{error && <p className="text-xs text-[color:var(--bz-danger,#b91c1c)] mt-0.5">{error}</p>}
</div>
);
}