0.0.74 ā€¢ Published 3 months ago

use-a11y-form v0.0.74

Weekly downloads
-
License
-
Repository
-
Last release
3 months ago

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

use-a11y-form Logo

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 object
  • asChild: use child as rendered element
  • validate: 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 element
  • auto: 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>
0.0.74

3 months ago

0.0.73

5 months ago

0.0.70

5 months ago

0.0.71

5 months ago

0.0.72

5 months ago

0.0.67

6 months ago

0.0.68

5 months ago

0.0.69

5 months ago

0.0.66

7 months ago

0.0.63

7 months ago

0.0.64

7 months ago

0.0.65

7 months ago

0.0.62

7 months ago

0.0.61

8 months ago

0.0.60

8 months ago

0.0.59

10 months ago

0.0.56

10 months ago

0.0.57

10 months ago

0.0.58

10 months ago

0.0.55

10 months ago

0.0.54

10 months ago

0.0.51

11 months ago

0.0.52

11 months ago

0.0.53

11 months ago

0.0.50

11 months ago

0.0.48

11 months ago

0.0.49

11 months ago

0.0.40

1 year ago

0.0.41

1 year ago

0.0.42

1 year ago

0.0.43

1 year ago

0.0.44

1 year ago

0.0.45

12 months ago

0.0.46

12 months ago

0.0.47

12 months ago

0.0.39

1 year ago

0.0.38

1 year ago

0.0.37

1 year ago

0.0.36

1 year ago

0.0.35

1 year ago

0.0.34

1 year ago

0.0.33

1 year ago

0.0.32

1 year ago

0.0.31

1 year ago

0.0.30

1 year ago

0.0.29

1 year ago

0.0.28

1 year ago

0.0.27

1 year ago

0.0.26

1 year ago

0.0.25

1 year ago

0.0.24

1 year ago

0.0.23

1 year ago

0.0.22

1 year ago

0.0.21

1 year ago

0.0.20

1 year ago

0.0.19

1 year ago

0.0.18

1 year ago

0.0.17

1 year ago

0.0.16

1 year ago

0.0.15

1 year ago

0.0.14

1 year ago

0.0.13

1 year ago

0.0.12

1 year ago

0.0.11

1 year ago

0.0.10

1 year ago

0.0.9

1 year ago

0.0.8

1 year ago

0.0.7

1 year ago

0.0.6

1 year ago

0.0.5

1 year ago

0.0.4

1 year ago

0.0.3

1 year ago

0.0.2

1 year ago

0.0.1

1 year ago