use-a11y-form v0.0.74
use-a11y-form š¤
React form hooks with a11y inclusive providers
- š¶ Super simple, accessible, multi-step + routed + tabbable forms friendly
- š¤ Compulsory accessibility. Aria labels and other good a11y practices are done by default
- š Headless. Integrates well with your existing components and stylings
Installation
npm i use-a11y-form
Getting started
import { useForm, Form } from 'use-a11y-form'
const SignIn = () => {
const form = useForm({
values: { email: '', password: '' },
validate: values => ({
name: !values.name && 'Enter a name',
password: !values.password && 'Enter a password',
}),
onSubmit: async (form, event) => {
// ... form.values
return 'Signed in successfully'
},
})
return (
<Form form={form}>
<Form.Field name='name'>
<Form.Label>Name</Form.Label>
<Form.Input auto='name' />
<Form.Error />
</Form.Field>
<Form.Field name='email'>
<Form.Label>Email</Form.Label>
<Form.Input type='email' auto='email' />
<Form.Error />
</Form.Field>
<Form.Assertive />
<Form.Submit>Continue</Form.Submit>
</Form>
)
}
Component behavior outside of form context
Some form components can be used outside of a <Form/>
context. Wrapping your label and input field with no form context will automatically generate and assign ids.
const Field = ({ label, name, ...props }) => {
return (
<div className='...'>
<Form.Field>
{/* Will render label with correct id binding to your input */}
<Form.Label>{label}</Form.Label>
<Form.Input {...props} className={cx('...', props.className)} />
{/* Will be ignored outside <Form/> */}
<Form.Error />
</Form.Field>
</div>
)
}
<div>
<label for="XY"></label>
<input id="XY"></label>
</div>
API Reference
useForm
Creates a new form api
useForm({
values, // initial values
validate, // values validations
onSubmit, // submit handler
translate, // error, assertive, ... translate fn
disabled, // defines if entire form disabled
valuesDependency, // defines if form should depend on changes do values object
allowSubmitAttempt, // alternative form behavior, allows a first invalid submit attempt
allowErrorSubmit, // allow submit when form still has errors
})
Form API
const form = useForm(...)
form.errors // form errors
form.values // form values
form.touched // touched fields
form.alert // assertive alert text
form.isSubmitting // defines if an async submit was called and is still unresolved
form.isValid // form is valid
form.isTouched // form was touched
form.isCompleted // form is completed
form.setValues({ name: value })
form.setValue("name", value)
form.setAssertive("Try again later.")
form.completed()
form.reset() // reset form state
form.reset({ ... }) // reset form state with values
Validation
The validate function recieves the current values and returns an object mapping fields to errors. Only strings are considered errors.
useForm({
values: { name: '' },
validate: values => ({ name: !name && '' }),
})
Validate values using vx
vx
is a validation helper function that allows you to chain-compose multiple validations for a single value.
({ password }) => ({
password: vx(
!password && "Enter a name",
password.length < 8 && "Password a longer password",
)
}),
Submit
The submit function recieves the current form object and values
useForm({
onSubmit: async ({ values, ...form }) => {
const { error } = await signIn(values)
if (error) return error // return assertive form error
form.complete() // the complete method will disable the form
},
})
Form providers
Form
Root form and context provider.
Parameters
form
: form api objectasChild
: use child as rendered elementvalidate
: whether to reenable standard html form validation
All form properties are also passed as data attributes: data-use-a11y-form
, data-submitting
, data-disabled
, data-submit-disabled
, data-touched
, data-completed
, data-valid
, data-invalid
, data-showing-errors
<Form form={form}>
{...}
</Form>
// or as child
<Form form={form} asChild>
<form />
</Form>
Form.Context
Makes field context accessible through callback. Useful for custom or complex input components.
Will throw an error if used outside <Form/>
<Form form={form}>
<Form.Context>
{form => {
form.isCompleted
}}
</Form.Context>
</Form>
Form.FieldSet
Wraps fields in a accessible fieldset
<Form.FieldSet name="name">{...}</Form.FieldSet>
Form.Field
Wraps field components like Form.Input
and Form.Label
with field context
<Form.Field name="name">
{...}
</Form.Field>
Form.FieldContext
Makes field context accessible through callback. Useful for custom or complex input components.
Will throw an error if used outside <Form.Field/>
<Form.Field name='country'>
<Form.FieldContext<string>>{field => <select value={field.value} />}</Form.FieldContext>
</Form.Field>
Form.Label
Create a label inside a field context
Parameters
asChild
: use child as rendered element
<Form.Field name='name'>
<Form.Label>Name</Form.Label>
</Form.Field>
Form.Input
Create an input inside a field context
Parameters
asChild
: use child as rendered elementauto
: pass a typed and accessible autocomplete
All input properties are also passed as data attributes: data-error
, data-touched
, data-has-hidden-error
, data-disabled
, data-field-context
<Form.Field name='name'>
<Form.Input />
{/* auto prop */}
<Form.Input /> {/* autoComplete="off" */}
<Form.Input auto /> {/* autoComplete="on" */}
<Form.Input auto={false} /> {/* autoComplete="off" */}
<Form.Input auto='given-name' /> {/* autoComplete="given-name" */}
</Form.Field>
Form.Error
Create an accessible input error inside a field context
Parameters
asChild
: use child as rendered element
<Form.Field name='name'>
<Form.Error />
</Form.Field>
Form.Assertive
Render assertive alert that may be returned from onSubmit
Parameters
asChild
: use child as rendered element
<Form form={form}>
<Form.Assertive />
{/* if provided with children, the alert will always be shown */}
<Form.Assertive>Something went wrong</Form.Assertive>
</Form>
Form.Submit
Render provided form submit
Parameters
asChild
: use child as rendered element
<Form form={form}>
<Form.Submit />
</Form>
vx
Validation helper
vx('Error A', 'Error B') // "Error A"
vx(false, 'Error B') // "Error B"
vx(false, false) // null
Context hooks
ā ļø Context hooks will throw an error if used outside their respective providers.
useFormContext
Access your form's context from your component
const form = useFormContext()
useFieldContext
Access your a field's context from your component
const form = useFieldContext<string>()
form.value // string
Adapters
createFieldAdapter
Creates a new field to component props adapter
const adaptRadio = createFieldAdapter((field) => ({ ..., checked: field.value }))
adaptSelect
Adapts a field context to work with select input
<Form.Field name='country'>
<Form.FieldContext>
{field => {
field.value // null | "afghanistan" | ...
}}
</Form.FieldContext>
<Form.FieldContext<Options>>
{adaptSelect(field => {
field.value // "" | "afghanistan" | ...
})}
</Form.FieldContext>
</Form.Field>
adaptCheckbox
Adapts a field context to work with a checkbox input
<Form.Field name='accept'>
<Form.FieldContext<boolean>>
{adaptCheckbox(props => (
<input {...props} />
))}
</Form.FieldContext>
</Form.Field>
4 months ago
6 months ago
6 months ago
6 months ago
6 months ago
7 months ago
7 months ago
6 months ago
8 months ago
9 months ago
9 months ago
9 months ago
9 months ago
9 months ago
9 months ago
11 months ago
11 months ago
11 months ago
11 months ago
11 months ago
11 months ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago