0.1.4 • Published 5 years ago

uninformed v0.1.4

Weekly downloads
2
License
ISC
Repository
github
Last release
5 years ago

Uninformed

Nostalgically simple forms for React and Preact.

npm install uninformed

You’ll also need either React >= 16 or Preact >= 8.

Why?

Forms in Rails do two useful things by default:

  • Send data to the server without refreshing the page
  • Prevent accidental double-submissions

Uninformed is a tiny library that brings these defaults to the React/Preact ecosystem.

Getting Started

import { Form } from 'uninformed';
import React from 'react';

export const SignupForm = () => (
  <Form action="/api/signups">
    <input type="email" name="email" required />
    <input type="submit" value="Sign Up" />
  </Form>
)

That’s it! No onChange handlers, no render props, just a lightly-enhanced HTML form that disables itself on submit, sends data to a server via AJAX, and re-enables itself after the server responds.

Basic Props

action

string | any valid URI

The URI of the service that will process your form, e.g. /api/signups

method

string | any valid HTTP verb | defaults to POST

The HTTP method to use when sending the form data, e.g. POST, PATCH, etc

enctype / encType

string | defaults to application/x-www-form-urlencoded

The encoding of the Form. Like the standard HTML enctype attribute, you can set this prop to multipart/form-data to support file uploads. Unlike the HTML enctype attribute, you can also set this prop to application/json to send JSON. Note that React expects form elements to have a camelCase encType prop instead of enctype. Uninformed supports either style and converts to camelCase internally.

onSubmit

function(event, payload) | optional

Called when a form is submitted. Use onSubmit to perform client-side validation, trigger updates to your UI, etc. You can return false from this function to prevent your Form from submitting.

beforeSend

function(xhr) | optional

Manipulate your form's XMLHttpRequest instance before sending. Use this prop set auth headers, configure CORS, etc:

const SignupForm = () => (
  <Form
    action="/api/signups"
    beforeSend={xhr => {
      // include auth credentials
      xhr.setRequestHeader("Authorization", `Bearer ${USER_AUTH_TOKEN}`);
      // parse response as JSON automatically
      xhr.responseType = "json";
      // add a pogress meter?
      xhr.addEventListener("progress", this.props.onProgressUpdate);
    }}
  >
    <input type="email" name="email" required />
    <input type="submit" value="Sign Up" />
  </Form>
);

onSuccess

function(xhr) | optional

Handle a successful form response.

const AuthForm = props => (
  <Form
    action="/login"
    onSuccess={xhr => {
      const user = JSON.parse(xhr.responseText);
      props.onLogin(user);
    }}
  >
    <input type="email" name="email" required />
    <input type="password" name="password" required />
    <input type="submit" value="Log In" />
  </Form>
);

onError

function(xhr) | optional

Handle a failed form response.

const AuthForm = () => (
  <Form
    action="/login"
    onError={xhr => {
      const error = JSON.parse(xhr.responseText);
      alert(`Error ${xhr.status}: ${error.message}`);
    }}
  >
    <input type="email" name="email" required />
    <input type="password" name="password" required />
    <input type="submit" value="Log In" />
  </Form>
);

Advanced Props

serialize

function(HTMLFormElement)

Use a custom serializer. The built-in serializers for url-encoded and multipart encodings follow the qs/Rails standard for nested object support, but the built-in JSON serializer doesn't support nested objects. Here's how you could serialize nested JSON with help from form-serialize.

import { Form } from "uninformed";
import serialize from "form-serialize";

const SignupForm = () => (
  <Form
    action="/signup"
    serialize={formElement => {
      const data = serialize(formElement, { hash: true });
      // data looks like this:
      //  {
      //    user: {
      //      name: 'abc',
      //      email: 'abc@123.com',
      //      interests: ['Ethics', 'Food'],
      //    },
      //  }
      return JSON.stringify(data);
    }}
  >
    <input type="user[name]" name="text" required />
    <input type="user[email]" name="email" required />
    <select multiple name="interests[]">
      <option value="Ethics">Ethics</option>
      <option value="Food">Food</option>
    </select>
    <input type="submit" value="Sign Up" />
  </Form>
);

send

function(payload, formInstance) => promise

Use a custom function to send your form data, instead of the XMLHttpRequest Uninformed uses by default. This function must return a Promise. Here's an example that uses the Fetch API:

const SignupForm = props => (
  <Form
    action="/api/signups"
    enctype="application/json"
    send={(payload, formInstance) => {
      const { method, action } = formInstance.props;
      return fetch(action, {
        headers: {
          "Content-Type": "application/json",
          Authorization: `Bearer ${props.authToken}`
        },
        method,
        body: payload
      }).then(res => res.json());
    }}
  >
    <input type="email" name="email" required />
    <input type="submit" value="Sign Up" />
  </Form>
);

Use In Preact

Uninformed is built as a library-agnostic factory function. To use it in Preact without a preact-compat, import the factory directly:

import { createForm } from 'uninformed/dist/factory';
import { h, Component } from 'preact';
const Form = createForm({ h, Component });

export default const SignupForm = () => (
  <Form action="/api/signups">
    <input type="email" name="email" required />
    <input type="submit" value="Sign Up" />
  </Form>
)

Browser Support

Uninformed supports modern browsers and IE11. If you use a custom send function, you will need to polyfill Promise support in IE.

Prior Art

None of these libraries handle submitting data or preventing double-submissions, but they do handle client-side validation.

Contributing

Bugs

Please open an issue on Github.

Pull Requests

PRs are welcome, and I'll do my best to review them promptly.

0.1.4

5 years ago

0.1.3

5 years ago

0.1.2

5 years ago

0.1.1

5 years ago

0.1.0

5 years ago