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

formgo

v0.2.4

Published

A simple, flexible, and powerful React form library, designed to help you build efficient and robust web forms.

Downloads

20

Readme

FormGo

npm version

A simple and flexible React form library, designed to help you build efficient and robust web forms.

Features

  • Easy-to-use API
  • Built-in validation with custom rules or Zod schema
  • Flexible error handling options
  • Highly customizable
  • Nested Fields Support
  • Nested Fields Validation

Installation

npm install formgo

or

yarn add formgo

or

pnpm add formgo

Usage

Here's a simple example of a form that uses FormGo. The errors and defaultValues are injected into child components by default and can be displayed conditionally based on the errors and defaultValues objects:

import React from 'react';
import Form from 'formgo';

function MyForm() {
  const handleSubmit = (formData) => {
    console.log('Form data:', formData);
  };

  return (
    <Form
      onSubmit={handleSubmit}
      validationRules={{
        name: {
          required: true,
          minLength: 2,
          maxLength: 30,
        },
        email: {
          required: true,
          pattern: /^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/,
        },
      }}
      customErrorMessages={{
        name: {
          required: 'Name is required',
          minLength: 'Name must be at least 2 characters',
        },
        email: {
          required: 'Email is required',
          pattern: 'Email format is invalid',
        },
      }}
      defaultValues={{ name: 'John', email: '[email protected]' }}
    >
      {(props: any) => (
        <>
          <label htmlFor="name">Name:</label>
          <input name="name" required defaultValue={props.defaultValues.name} />
          {props.errors.name && <span>{props.errors.name}</span>}

          <label htmlFor="email">Email:</label>
          <input
            name="email"
            type="email"
            required
            defaultValue={props.defaultValues.email}
          />
          {props.errors.email && <span>{props.errors.email}</span>}

          <button type="submit">Submit</button>
        </>
      )}
    </Form>
  );
}

export default MyForm;

Note on the name attribute in form fields

For FormGo to function correctly and gather form data, it's essential to assign a name attribute to every form field. This attribute helps the library identify and capture the value of each field upon form submission.

In the examples provided, you'll notice the name attribute being used:

<input name="name" required />
<input name="email" type="email" required />

Ensure that every form field in your FormGo forms has a unique name attribute, as this is pivotal for the correct operation of the library.

API Reference

<Form />

The Form component is the heart of your form. It can optionally accept a ref to provide a method to reset the form.

Props

  • onSubmit (data: any) => void: Function called when the form is submitted.
  • validationRules? { [key: string]: ValidationRule }: Optional custom validation rules. Zod schema is prioritized over this if both are provided.
  • customErrorMessages? { [key: string]: CustomErrorMessages }: Optional custom error messages.
  • validationSchema? ZodSchema: Optional Zod schema for validation.
  • onError? (errors: any) => void: Optional function called when validation errors occur.
  • onFieldChange? (fieldName: string, fieldValue: any) => void: Optional function called when a field changes.
  • onFormChange? (formData: any) => void: Optional function called when any part of the form changes.
  • className? string: Optional class name to be added to the form element.
  • style? React.CSSProperties: Optional inline styles to be applied to the form element.
  • defaultValues? Record<string, any>: Optional object containing default values for form fields.
  • onEnterSubmit? boolean: Optional onEnterSubmit prop, let you enable or disable form submission when the user presses the Enter key. By default, this prop is set to true.
  • onEnterSubmit? boolean: Optional onEnterSubmit prop, let you enable or disable form submission when the user presses the Enter key. By default, this prop is set to true.
  • includeDataToCallBack? boolean: Optional includeDataToCallBack prop, let you include the formdata in the callback function. By default, this prop is set to false.

Ref

When a ref is passed to the Form component, it provides the following method:

  • resetForm(): void: Method to reset the form to its initial state. It clears all field values and validation errors.
  • submit(): void: Method to manually trigger submit of the form.
Example of using ref to reset the form:
import React, { useRef } from 'react';
import Form from 'formgo';

function MyForm() {
  const formRef = useRef<{ resetForm: () => void }>(null);

  const handleSubmit = (formData) => {
    console.log('Form data:', formData);
  };

  const handleReset = () => {
    formRef.current?.resetForm();
  };

  return (
    <>
      <Form ref={formRef} onSubmit={handleSubmit}>
        {/* ... */}
      </Form>
      <button onClick={handleReset}>Reset Form</button>
    </>
  );
}

export default MyForm;

Validation

FormGo supports powerful validation. Use custom validation rules with optional custom error messages or a Zod schema:

Custom Validation Rules with Custom Error Messages:

<Form
  onSubmit={handleSubmit}
  validationRules={{
    name: {
      required: true,
      minLength: 2,
      maxLength: 30,
    },
    email: {
      required: true,
      pattern: /^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/,
    },
  }}
  customErrorMessages={{
    name: {
      required: 'Name is required',
      minLength: 'Name must be at least 2 characters',
    },
    email: {
      required: 'Email is required',
      pattern: 'Email format is invalid',
    },
  }}
>
  {/* ...form fields... */}
</Form>

Zod Schema Validation:

import { z } from 'zod';
import Form from 'formgo';

const userSchema = z.object({
  name: z.string().min(2).max(30),
  email: z.string().email(),
});

<Form onSubmit={handleSubmit} validationSchema={userSchema}>
  {/* ...form fields... */}
</Form>;

Nested Fields Support

FormGo now supports deeply nested objects for form validation. You can define validation rules and custom error messages for nested fields. The nesting can go multiple levels deep.

Example of Nested Fields with Custom Validation Rules:

<Form
  onSubmit={handleSubmit}
  validationRules={{
    userinfo: {
      name: {
        required: true,
        minLength: 2,
        maxLength: 30,
      },
      address: {
        street: {
          required: true
        },
        postal: {
          code: {
            required: true
          }
        }
      }
    }
  }}
  customErrorMessages={{
    userinfo: {
      name: {
        required: 'Name is required',
        minLength: 'Name must be at least 2 characters',
      },
      address: {
        street: {
          required: 'Street is required'
        },
        postal: {
          code: {
            required: 'Postal code is required'
          }
        }
      }
    }
  }}
  defaultValues={{ userinfo: { name: 'John', address: { street: '123 Main St', postal: { code: '12345' } } } }}
>
  {(props: any) => (
    <>
      <label htmlFor="userinfo.name">Name:</label>
      <input name="userinfo.name" required defaultValue={props.defaultValues.userinfo.name} />
      {props.errors.userinfo?.name && <span>{props.errors.userinfo.name}</span>}

      <label htmlFor="userinfo.address.street">Street:</label>
      <input name="userinfo.address.street" required defaultValue={props.defaultValues.userinfo.address.street} />
      {props.errors.userinfo?.address?.street && <span>{props.errors.userinfo.address.street}</span>}

      {/* ... More fields ... */}
      
      <button type="submit">Submit</button>
    </>
  )}
</Form>

Accessing Nested Errors:

When using nested fields, you can access the nested errors in the errors object in your child component function.

{props.errors.userinfo?.name && <span>{props.errors.userinfo.name}</span>}
{props.errors.userinfo?.address?.street && <span>{props.errors.userinfo.address.street}</span>}

Zod Schema Support for Nested Fields:

If you are using Zod for validation, nested validation is also supported.

import { z } from 'zod';

const userSchema = z.object({
  userinfo: z.object({
    name: z.string().min(2).max(30),
    address: z.object({
      street: z.string(),
      postal: z.object({
        code: z.string()
      })
    })
  })
});

<Form onSubmit={handleSubmit} validationSchema={userSchema}>
  {/* ...form fields... */}
</Form>

Error Handling

By default, the errors object is injected into child components. If you want more control over error handling, use the onError prop:

function MyForm() {
  const handleError = (errors) => {
    console.log('Validation errors:', errors);
  };

  return (
    <Form
      onSubmit={handleSubmit}
      validationSchema={userSchema}
      onError={handleError}
    >
      <label htmlFor="name">Name:</label>
      <input name="name" required />

      <label htmlFor="email">Email:</label>
      <input name="email" type="email" required />

      <button type="submit">Submit</button>
    </Form>
  );
}

Using Children as a Function

When you utilize the children of the Form component as a function, it allows you to access both errors and defaultValues as arguments to that function. This is especially useful when you want to initialize your form fields with some default values:

<Form
  onSubmit={handleSubmit}
  defaultValues={{ name: 'John', email: '[email protected]' }}
>
  {(props: any) => (
    <>
      <label htmlFor="name">Name:</label>
      <input name="name" required defaultValue={props.defaultValues.name} />
      {props.errors.name && <span>{props.errors.name}</span>}

      <label htmlFor="email">Email:</label>
      <input
        name="email"
        type="email"
        required
        defaultValue={props.defaultValues.email}
      />
      {props.errors.email && <span>{props.errors.email}</span>}

      <button type="submit">Submit</button>
    </>
  )}
</Form>

Using children not as a function

If you don't use the children as a function i.e

<Form onSubmit={handleSubmit} defaultValues={{ name: 'John', email: '[email protected]' }}>
  <>
    <label htmlFor="name">Name:</label>
    <input name="name" required />

    <label htmlFor="email">Email:</label>
    <input name="email" type="email" required />

    <button type="submit">Submit</button>
  </>
</Form>

In this scenario, you won't have access to the defaultValues prop directly in the form fields. To initialize fields with default values, you would need to use the function approach.


Contributing

Your contributions to FormGo are welcome!

License

FormGo is MIT licensed.