Skip to content
This repository has been archived by the owner on Feb 20, 2022. It is now read-only.

oaf-project/oaf-react-final-form

Repository files navigation

Oaf React Final Form

Build Status type-coverage Codecov Mutation testing badge

Known Vulnerabilities npm

An opinionated form library.

  • TypeScript + React Final Form
  • Strict type safety
  • Validation built with io-ts
  • Accessible by default
    • By default we render accessible form labels and validation feedback (with aria-invalid and aria-labelledby)
    • We follow the guidance from https://www.tpgi.com/required-attribute-requirements/
      • We use the novalidate attribute on the form element to disable browsers’ client-side validation. Instead, we implement custom validation and accessible error messaging.
      • To ensure most screen readers won’t default to announcing required form controls as invalid, we use aria-invalid="false". We update this to true if the current value (or lack thereof) of a required control does not pass validation.
      • We use aria-describedby on required form controls to point to the element that contains the inline error message.
      • We wait until the control has lost focus before marking a form control as invalid and displaying the inline error message. We do this by defaulting React Final Form's validateOnBlur option to true. See final-form/final-form#250. As a consequence, we include work-arounds for final-form/final-form#213 and final-form/react-final-form#458
    • After a failed form submission, we move focus to the first invalid form element (using https://github.com/oaf-project/oaf-side-effects)
    • We follow the advice from https://webaim.org/techniques/formvalidation/

Installation

# yarn
yarn add oaf-react-final-form

# npm
npm install oaf-react-final-form

Usage

  // First, we define the form codec using io-ts.
  // See https://github.com/gcanti/io-ts#the-idea
  //
  // `formCodec` is just a convenience function over the top of
  // `intersection`, `type`, `partial` and `readonly` from io-ts.
  // See https://github.com/gcanti/io-ts#mixing-required-and-optional-props
  const codec = formCodec({
    optional: {
      foo: t.string,
    },
  });

  // We derive React components for our form elements from the form codec. This
  // gives us some type-safety benefits when rendering these form elements (below).
  const { Form, Input, Select } = elementsForCodec(codec);

  type FormData = t.TypeOf<typeof codec>;

  const onSubmit = (formData: FormData): SubmissionResponse<FormData> => {
    // Here we are guaranteed that `formData` has been parsed by our form codec.
    // We can return submission errors here if necessary.
    return undefined;
  };

  const form = (
    <Form onSubmit={onSubmit}>
      {/*
        The `name` attr must be one of the values from the form codec.
        The `type` and `required` attrs must be compatible with the corresponding property from the form codec.
          * Because `foo` is optional in the codec, `required` must be either undefined or false.
          * Because `foo` is a string in the codec, `type` cannot be one of the numeric input types (`number` or `range`).
      */}
      <Input label="foo" name="foo" type="text" />
    </Form>
  );

See Form.test.tsx for more examples.

Other Form Accessibility Tips