npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

use-a11y-form

v0.0.74

Published

React form hooks with a11y inclusive providers

Downloads

365

Readme

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>