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>
3 months ago
5 months ago
5 months ago
5 months ago
5 months ago
6 months ago
5 months ago
5 months ago
7 months ago
7 months ago
7 months ago
7 months ago
7 months ago
8 months ago
8 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 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
12 months ago
12 months ago
12 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