Forms
TextInput
Pill text field with label, required marker, error message and uppercase mode.
npx bezel-add add text-inputpackages/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>
);
}