Input
Compound component for text inputs. Works controlled and uncontrolled. Validation is entirely consumer-controlled — set invalidType to trigger the error state.
Features
Compound component with Label, Field, and Error parts.
Consumer-controlled validation via invalidType.
Success state support via isSuccess.
Can be controlled or uncontrolled.
Automatic aria-invalid and aria-required attributes.
Example
Anatomy
import { Input } from '@wire-ui/react'
<Input.Root>
<Input.Label>Full Name</Input.Label>
<Input.Field placeholder="John Doe" />
</Input.Root>Styling
Input exposes validation and focus states via data attributes on the Field element. Style error, success, and active states using attribute selectors.
<Input.Field className="
border border-black
data-[active]:border-blue-500
data-[invalid]:border-red-500
data-[success]:border-green-500
" />Using data attributes
Input.Field reflects the current state through data attributes set by the Root component.
/* Active (focused) */
input[data-active] { border-color: #3b82f6; }
/* Invalid (consumer-controlled via invalidType) */
input[data-invalid] { border-color: #ef4444; }
/* Success (consumer-controlled via isSuccess) */
input[data-success] { border-color: #22c55e; }Root props
| Prop | Type | Default | Description |
|---|---|---|---|
value | string | — | Controlled value |
defaultValue | string | '' | Initial value for uncontrolled use |
onChange | (value: string) => void | — | Called on every keystroke |
onFocus | () => void | — | Called when field gains focus |
onBlur | () => void | — | Called when field loses focus |
invalidType | string | '' | Key into errorMessage; set by consumer when invalid |
errorMessage | Record<string, string> | {} | Map of error keys to display strings |
isRequired | boolean | false | Shows * in label; sets aria-required |
isSuccess | boolean | false | Adds data-success to field |
id | string | auto-generated | Links label htmlFor to field id |
Field data attributes
| Attribute | When present |
|---|---|
data-active | Field is focused |
data-invalid | invalidType is non-empty |
data-success | isSuccess is true |
aria-invalid="true" and aria-required="true" are also set automatically.
Validation pattern
wire-ui does not validate — you decide when and what is invalid:
const [value, setValue] = useState('')
const [invalidType, setInvalidType] = useState('')
function handleBlur() {
if (!value) setInvalidType('required')
else setInvalidType('')
}
function handleSubmit() {
if (!value) { setInvalidType('required'); return }
// proceed...
}
<Input.Root
value={value}
onChange={setValue}
invalidType={invalidType}
errorMessage={{ required: 'This field is required' }}
>
<Input.Field onBlur={handleBlur} />
<Input.Error />
</Input.Root>Last updated on