Forms
doodleui-react form controls work with native HTML forms, FormData, and react-hook-form.
Native attributes
Input, Textarea, NativeSelect, and Radix-backed controls forward name, required, disabled, pattern, minLength, maxLength, min, and max where applicable.
<form
onSubmit={(e) => {
e.preventDefault();
const data = new FormData(e.currentTarget);
console.log(Object.fromEntries(data));
}}
>
<Input name="email" label="Email" required type="email" />
<Checkbox name="terms" value="yes" label="Accept" />
<RadioGroup name="plan" defaultValue="pro">
<Radio value="free" label="Free" />
<Radio value="pro" label="Pro" />
</RadioGroup>
<Select name="fruit" options={OPTIONS} aria-label="Fruit" />
<button type="submit">Save</button>
</form>
react-hook-form: register()
Use register() for native elements — Input and Textarea (and NativeSelect).
const { register, handleSubmit } = useForm();
<form onSubmit={handleSubmit(onSubmit)}>
<Input label="Email" {...register("email", { required: true })} />
<Textarea label="Notes" {...register("notes")} />
</form>
react-hook-form: Controller
Use Controller for Radix button-based controls — Checkbox, Switch, RadioGroup, Select.
<Controller
name="accept"
control={control}
render={({ field }) => (
<Checkbox
label="Accept"
checked={field.value}
onCheckedChange={field.onChange}
name={field.name}
/>
)}
/>
Validation styling
Set invalid / error / errorMessage on form controls. When invalid, the sketch stroke uses --doodle-ui-color-error and aria-invalid="true" is set automatically. Messages are linked with aria-describedby.
<Input label="Email" error="Required" />
Prefer composing with Field for label + description + error wiring across a control.