Child components
Directives are compile-time syntax, not values. use:validate cannot be forwarded as a prop, spread onto a child, or stored in a variable and applied later. Once a field moves into its own component, the directive stops being an option.
validateRef is the same registration behind a plain ref function:
// Parentfunction ProfileForm() { const { formSubmit, validateRef, errors } = useForm();
return ( <form use:formSubmit={onSubmit}> <HandleField validateRef={validateRef} error={errors.handle} /> <button type='submit'>Save</button> </form> );}// Childtype ValidateRef = ReturnType<typeof useForm>['validateRef'];
function HandleField(props: { validateRef: ValidateRef; error?: string }) { return ( <input name='handle' required ref={props.validateRef(minLength(3), noSpaces)} /> );}Validators are passed as arguments rather than as an array, and the child decides what they are. The parent supplies the registration function and never learns what rules the field applies. Adding a rule to HandleField changes nothing in ProfileForm.
With no validators, native constraints still apply:
<input name='email' type='email' required ref={props.validateRef()} />Passing errors down
The errors store is a Solid store proxy, so reading errors.handle in the parent and passing the result as a prop stays reactive. Passing the whole store down also works if a child needs several keys:
<AddressFields validateRef={validateRef} errors={errors} />One useForm per form
useForm creates an independent store and field registry each time it is called. A child that calls useForm itself gets its own form, and its fields will not be checked when the parent submits. Call it once at the top of the form and pass validateRef down.