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

react-easy-form-hook

v0.1.2

Published

A headless hook for creating forms in react. Created to be fast, configurable and easy to use.

Downloads

3

Readme

Easy React Headless Forms

Features

  • Strongly typed
  • Easily configurable
  • Fast
  • Supports dependent dropdowns
  • Comes with built-in html field factory
  • Can be used with other UI libraries

Table of contents

Examples

Simple

Let's create a simplest possible form with user data, address and start date

import React, { useMemo } from 'react';
import { FieldFactory, useForm, FieldSettings, FieldType } from 'easy-react-form-hook';

export function SimpleForm() {

    const fields = useMemo(() => [
        { type: FieldType.Text, accessor: "firstName", label: "First Name", },
        { type: FieldType.Text, accessor: "lastName", label: "Last Name", },
        { type: FieldType.Text, accessor: "city", label: "City", },
        { type: FieldType.Text, accessor: "street", label: "Street", },
        { type: FieldType.Date, accessor: "startDate", label: "startDate", },
    ] as FieldSettings[], []);

    const form = useForm({ fieldsSettings: fields });
    const submit = (object:  any) => {/** you api call here */}

    return <>
        {form.fields.map(field => <div key={field.accessor}><FieldFactory {...field} /></div>)}
        <button disabled={ (!form.formState.valid && !form.formState.changed)} onClick={() => submit(form.object)}>Submit</button>
    </>;
}

FieldFactory, will handle creation of all field types in following format

<label {...field.labelAttributes}>{field.label}</label>
<input {...field.attributes} />

or

<label {...field.labelAttributes}>{field.label}</label>
<select {...field.attributes}>
        {field.options?.map(option => <option key={option.value} {...option} />)}
</select>

You can always implement your own factory

Nested Objects

Same as above, just change accessors and it is done.

import React, { useMemo } from 'react';
import { FieldFactory, useForm, FieldSettings, FieldType } from 'easy-react-form-hook';

export function SimpleForm() {

    const fields = useMemo(() => [
        { type: FieldType.Text, accessor: "user.firstName", label: "First Name", },
        { type: FieldType.Text, accessor: "user.lastName", label: "Last Name", },
        { type: FieldType.Text, accessor: "address.city", label: "City", },
        { type: FieldType.Text, accessor: "address.street", label: "Street", },
        { type: FieldType.Date, accessor: "startDate", label: "startDate", },
    ] as FieldSettings[], []);

    const form = useForm({ fieldsSettings: fields });
    const submit = (object:  any) => {/** you api call here */};

    return <>
        {form.fields.map(field => <div key={field.accessor}><FieldFactory {...field} /></div>)}
        <button disabled={ (!form.formState.valid && !form.formState.changed)} onClick={() => submit(form.object)}>Submit</button>
    </>;
}

RegExp validation

Field is validated using RegExp everytime if regex property is provided and onChange event is called./ RegExp is also provided to field as attribute pattern so it is calculated by browser as well. This allows to use css with selector such as input:valid or input:invalid. Also <input type='submit'> can laverage this validation as well.

Based on previous example, let's change input user.fistName and add regex.

    { type: FieldType.Text, accessor: "firstName", label: "First Name", regex: /[a-zA-Z]{2,15}/, },

If any of the fields in the form are not valid or not populated when required, state of the form is set to invalid form.formState.valid = false.

API

useForm

import { useForm } from 'east-react-from-hook'

const form = useForm(settings)

settings: FormSettings

export interface FormSettings<TObject, TCustomProps> {
    fieldsSettings: FieldSettings<TCustomProps>[];
    defaultSettings?: DefaultFieldSettings<TCustomProps>;
    initialState?: TObject;
    disabled?: boolean;
    keepEmptyProperties?: boolean;
    refreshObjectOnChange?: boolean;
    formName?: string;
}
  • fieldSettings

    • List of fields handled by form e.g.
    const fields =[
        { type: FieldType.Text, accessor: "name", label: "Name", },
        { type: FieldType.TextArea, accessor: "comment", label: "Comment",},
    ]
  • defaultSettings

    • Default field settings that will be marged with all provided fields.
  • initialState

    • Object from which, values will be read. If not provided, object will be initialized to empty object {}
  • disabled

    • disables all form fields
  • keepEmptyProperties

    • By default, fields with value = undefined, will not be included in object.
      On the example of fields above. If keepEmptyProperties is false or udefined and user hasn't populated input fields, then resulting object will be {} If user have only populated field name with value John Smith, then form object will look as below
        {
            name: "John Smith"
        }

    If both fields were populated, then form object will have both properties

        {
            name: "John Smith",
            comment: "This is a new user",
        }
  • refreshObjectOnChange

    • If you don't need your object to be recreated on every onChange event, then you can set this property to false. To create a form object on demand, use function getObject: () => TObject; from IForm interface returned by useForm hook.
  • formName

    • name of the form that will be added to every field as a field attribute form

FieldSettings<TCustomProps>

Depending on the field type selected, there will be different options and field attribute to set. However, all fields have following properties in common

    type: FieldType;
    accessor: string;
    disabled?: boolean;
    label: string;
    tag?:string;
  • type: FieldType

    • Directly corresponds to HTML input field types. Based on selected FieldType, type of FieldSettings object will change and different properties and field attributes will be accepted.
    enum FieldType {
        Checkbox = "checkbox",
        Color = "color",
        Date = "date",
        DateRange = "dateRange",
        Email = "email",
        File = "file",
        Month = "month",
        Number = "number",
        NumericRange = "numberRange",
        Range = "range",
        Radio = "radio",
        Passowrd = "password",
        Search = "search",
        Select = "select",
        SelectMultiple = "multiselect",
        Submit = "submit",
        Telephone = "tel",
        Text = "text",
        TextArea = "textarea",
        Time = "time",
        Week = "week",
    }
  • accessor

    • A path to property in object, using js notation style. E.g., in object
    {
        user: {
            firstName: "John",
            lastName: "Smith",
            address: {
                street: "Main St."
                city: "New Town"
            }
        },
        comment: "This is a new user",
    
    }

    we have following accessors
    user.firstName
    user.lastName
    user.address.street
    user.address.city
    comment\

  • disabled

    • Permanently disables a field
  • label

    • label used for HTML tag <label>label value goes here</label>
  • tag

    • Since this is a headless form, you might decide that you want to split this object to multiple tabs (e.g., Personal Information, Address, Account Data).
      tag can be used to filter fields and use them in different parts of your app

DefaultFieldSettings<TCustomProps>

Object used to provide properties and field attributes that will be merged with all fields. If specific field settings provide the same attributes, they will override default settings.

    className?: string;
    classNameLabel?: string;
    customProps?: TCustomProps;
    type?: FieldType;

IForm<TObject, TCustomProps>

Objet returned by hook useForm

    fields: FormField<TCustomProps>[];
    formState: IFormState;
    object: TObject;
    getObject: () => TObject;

object: TObject

Object created from all the fields.

getObject: () => TObject

Function used to get final object when a `refreshObjectOnChange` is set to false.

fields: FormField[]

List of fields to be rendered. There are multiple type of fields with following attributes in common.

    accessor: string;
    accessors: string[];
    customProps?: TCustomProps;
    disabled?: boolean;
    initialValue?: string | number;
    labelAttributes?: FormFieldLabel;
    tag?:string;
    value?: any;
  • accessor

  • accessors

    • Array created by spitting accessor by dot ".". It is used internally to speed up updating form object.
  • customProps

    • Object defined by user that was provided in FieldSettings
  • disabled

    • Indicates if field is disabled
  • initialValue

    • Value taken from object provided as initialState in FormSettings. It is used to decide if form field and consequently whole from has been change. See formState: IFormState changed.
  • labelAttributes

    • attributes passed to <label> tag. Consists of following attributes
    id?: string
    className?: string,
    htmlFor?: string,
  • tag

    • A sdescribed in section [FieldSettings<TCustomProps>]
  • value

    • Current value of field. It is of a type approperiate for given FieldType

formState: IFormState

Object used to keep various information about the Form

    /** Defines if all fields with validation are valid */
    valid: boolean;
    /** Has form changed from inital value */
    changed: boolean;
    /** If true, properties that are undefined will set to null, otherwise thwy will not be created in final Object */
    keepEmptyProperties?: boolean;
    /** Is form dissabled */
    disabled?: boolean;
    /** If true, final object will be recreated every time onChange event is called on any input */
    refreshObjectOnChange?: boolean;