Code Monkey home page Code Monkey logo

remix-validated-form's Introduction

Remix Validated Form

A form library built for remix to make validation easy.

  • Client-side, field-by-field validation (e.g. validate on blur) and form-level validation
  • Set default values for the entire form in one place
  • Re-use validation on the server
  • Show validation errors from the server even without JS
  • Detect if the current form is submitting when there are multiple forms on the page
  • Validation library agnostic

Demo

example.mov

Getting started

Install

npm install remix-validated-form

Create an input component

In order to display field errors or do field-by-field validation, it's recommended to incorporate this library into an input component using useField.

import { useField } from "remix-validated-form";

type MyInputProps = {
  name: string;
  label: string;
};

export const MyInput = ({ name, label }: InputProps) => {
  const { validate, clearError, defaultValue, error } = useField(name);
  return (
    <div>
      <label htmlFor={name}>{label}</label>
      <input
        id={name}
        name={name}
        onBlur={validate}
        onChange={clearError}
        defaultValue={defaultValue}
      />
      {error && <span className="my-error-class">{error}</span>}
    </div>
  );
};

Create a submit button component

To best take advantage of the per-form submission detection, we can create a submit button component.

import { useIsSubmitting } from "../../remix-validated-form";

export const MySubmitButton = () => {
  const isSubmitting = useIsSubmitting();
  return (
    <button type="submit" disabled={isSubmitting}>
      {isSubmitting ? "Submitting..." : "Submit"}
    </button>
  );
};

Use the form!

Now that we have our components, making a form is easy!

import { ActionFunction, LoaderFunction, redirect, useLoaderData } from "remix";
import * as yup from "yup";
import { validationError, ValidatedForm, withYup } from "remix-validated-form";
import { MyInput, MySubmitButton } from "~/components/Input";

// Using yup in this example, but you can use anything
const validator = withYup(
  yup.object({
    firstName: yup.string().label("First Name").required(),
    lastName: yup.string().label("Last Name").required(),
    email: yup.string().email().label("Email").required(),
  })
);

export const action: ActionFunction = async ({ request }) => {
  const fieldValues = validator.validate(
    Object.fromEntries(await request.formData())
  );
  if (fieldValues.error) return validationError(fieldValues.error);
  const { firstName, lastName, email } = fieldValues.data;

  // Do something with correctly typed values;

  return redirect("/");
};

export const loader: LoaderFunction = () => {
  return {
    defaultValues: {
      firstName: "Jane",
      lastName: "Doe",
      email: "[email protected]",
    },
  };
};

export default function MyForm() {
  const { defaultValues } = useLoaderData();
  return (
    <ValidatedForm
      validator={validator}
      method="post"
      defaultValues={defaultValues}
    >
      <MyInput name="firstName" label="First Name" />
      <MyInput name="lastName" label="Last Name" />
      <MyInput name="email" label="Email" />
      <MySubmitButton />
    </ValidatedForm>
  );
}

Validation Library Support

This library currently includes an out-of-the-box adapter for yup, but you can easily support whatever library you want by creating your own adapter.

And if you create an adapter for a library, feel free to make a PR on this library to add official support ๐Ÿ˜Š

Creating an adapter

Any object that conforms to the Validator type can be passed into the the ValidatedForm's validator prop.

type FieldErrors = Record<string, string>;

type ValidationResult<DataType> =
  | { data: DataType; error: undefined }
  | { error: FieldErrors; data: undefined };

type ValidateFieldResult = { error?: string };

type Validator<DataType> = {
  validate: (unvalidatedData: unknown) => ValidationResult<DataType>;
  validateField: (
    unvalidatedData: unknown,
    field: string
  ) => ValidateFieldResult;
};

In order to make an adapter for your validation library of choice, you can create a function that accepts a schema from the validation library and turns it into a validator.

The out-of-the-box support for yup in this library works like this:

export const withYup = <Schema extends AnyObjectSchema>(
  validationSchema: Schema
  // For best result with Typescript, we should type the `Validator` we return based on the provided schema
): Validator<InferType<Schema>> => ({
  validate: (unvalidatedData) => {
    // Validate with yup and return the validated & typed data or the error

    if (isValid) return { data: { field1: "someValue" }, error: undefined };
    else return { error: { field1: "Some error!" }, data: undefined };
  },
  validateField: (unvalidatedData, field) => {
    // Validate the specific field with yup

    if (isValid) return { error: undefined };
    else return { error: "Some error" };
  },
});

remix-validated-form's People

Contributors

airjp73 avatar

Watchers

James Cloos avatar

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.