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 🙏

© 2025 – Pkg Stats / Ryan Hefner

react-superior-forms

v1.4.0

Published

A simple yet convenient way to build forms in react.

Downloads

28

Readme

Logo

Helps you easily build a form with input processing, validation and formatting.

npm install react-superior-forms

Features include:

Aims for customizable UI with classes, includes minimal CSS.

1. Introduction:

A basic form to create a user:

import Form, {TextInput, NumberInput, SubmitButton} from 'react-superior-forms';

<Form route="/create/user" json={true}>
    <label>Username</label>
    <TextInput name="username"/>

    <label>Favourite Number</label>
    <NumberInput name="favourite_number" process={true}/>

    <SubmitButton/>
</Form>;

Example request:

{username: "edward_baldwin", favourite_number: 10}

Let's put the fields into groups!

import Form, {InputGroup, TextInput, NumberInput, SubmitButton} from 'react-superior-forms';

<Form route="/create/user" json={true}>
    <InputGroup name="user">
        <label>Username</label>
        <TextInput name="username"/>
    </InputGroup>

    <InputGroup name="user_preferences">
        <label>Favourite Number</label>
        <NumberInput name="favourite_number" process={true}/>
    </InputGroup>

    <SubmitButton/>
</Form>;

Example request:

{user: {username: "edward_baldwin"}, user_preferences: {favourite_number: 10}}

Let's repeat these fields!

import Form, {InputGroupRepeater, TextInput, NumberInput, SubmitButton} from 'react-superior-forms';

<Form route="/create/users" json={true}>
    <InputGroupRepeater name="users" entries={2} minEntries={1} maxEntries={5}>
        <label>Username</label>
        <TextInput name="username"/>

        <label>Favourite Number</label>
        <NumberInput name="favourite_number" process={true}/>
    </InputGroupRepeater>

    <SubmitButton/>
</Form>;

Example request:

{
    users: [
        {username: "edward_baldwin", favourite_number: 10},
        {username: "gordo_stevens", favourite_number: 22}
    ]
}

2. Format, Process, Validate

It is important to understand the concept react-superior-forms uses to manage the values of the inputs. Each step is optional. Formatting removes all the junk from the input value. Processing will transform the value into the desired type. Validating will check whether the value passes all constraints.

For example, let's say we have a number field with all steps enabled:

<NumberInput name="favourite_number" format={true} process={true} validate={'max:10'} defaultValue="b58a"/>
  • Initial value: "b58a" (string)
  • After formatting: "58" (string)
  • After processing: 58 (number)

Now the validation can easily proceed with statement: 58 <= 10
Had we skipped the processing, the value would have remained a string, causing the validation to check whether the length of string "58" is less or equal to 10 using statement: "58".length <= 10
This flow will help us write reuseable validations for multiple scenarios, such as arrays, strings, numbers and more!

3. Components

3.1. Form

The <Form/> component, just like the native <form/> element, is responsible for collecting all input data of its childrens and handling the submit event.
The <Form/> component only recognizes the <Input/> components as inputs, and will ignore all other native elements such as <input/>, <select/>, <textarea/>, etc.

The submit data is available in both JSON and FormData.

Example usage:

import Form from 'react-superior-forms';

<Form
    route="/user/3/update"
    method="PATCH"
    json={true}
>
...
</Form>

Example rendered element:

<form class="rsf-form">
...
</form>

or

<form class="rsf-form rsf-form--invalid">
...
any invalid input (recursively)
...
</form>

Parameters:

| Parameter | Description | Type | Example value(s) | Default | | - | - | - | - | - | | route | The endpoint to submit the data to | string | "/example" | "/" | | method | The method used when submitting the data | string | "GET", "POST", "PATCH", etc. | "POST" | | json | Whether to submit the data in JSON (also sets the Content-type header to application/json) | boolean | false = submits FormDatatrue = submits JSON | false | | headers | The headers to send with the submitted request | object | {'X-CSRF-TOKEN': csrfToken} | null | | className | The classname to append to the list of classes. | string | "my-form" | null | | onSuccess | The function to call when the submit results in success (Status is 200) | function | (response, event, data) => console.log(event, data) | null | | onFail | The function to call when the submit results in failure (Status is not 200) | function | (response, event, data) => console.log(event, data) | null | | onSend | The function to call before sending the XHR | function | (data) => console.log(data) | null | | onSubmit | The function to call when trying to submit. If it returns 'false' then the form will not proceed to submit. | function | () => console.log('Trying to submit!') | null | | inputDefaults | The default props the <Input/> components will inherit. | object | {validate : true, hideValidateMessage: true, required: true, disabled: true, process: true, format: true}Check out the <Input/> props here. | null |

3.2. Input

The <Input/> component is recognized as an input of the <Form/> component and will be included in the submitted data if the disabled property is not set to false.
This component should only be used when creating a custom input of your own choice. A handful of inputs were already created to help you skip this process. Check out the basic inputs.

To create a custom input, pass your custom input component as the component property.
This component will inherit a handful of properties passed to the <Input> component (e.g. name, value, type, disabled, required, className) plus the current value of the input, and the onChange function which should be called whenever your input component's value has changed.

Example usage:

import Form, {Input, SubmitButton} from 'react-superior-forms';

const YourCustomInputComponent = React.forwardRef((props, ref) => {
    return <input type="text" disabled={props.disabled} onChange={(ev) => props.onChange(ev.target.value)} value={props.value ?? ''} ref={ref}/>;
});

<Form route="/example">
    <Input name="custom_stuff" component={<YourCustomInputComponent/>} disabled={Math.random() >= 0.5}/>
    <SubmitButton/>
</Form>;

Example output:

<form class="rsf-form">
    <input type="text" disabled>
</form>

or if "validate" property is used, and the input is currently invalid

<form class="rsf-form rsf-form--invalid">
    <div class="rsf-input-validation-wrapper rsf-input-validation-wrapper--invalid">
        <input type="text">
        <label>Validation error message</label>
    </div>
</form>

Parameters:

| Parameter | Description | Type | Example value(s) | Default | | - | - | - | - | - | | name | The key to use when submitting the data | string | "username" | "" | | defaultValue | The value to initialize the input with | any | "edward_baldwin", 123, [1,2,3] | null | | type | The input type. This helps in recognizing the default validator, formatter when they are set to auto (true). | "email", "password", "text", "number", "custom" | "text" | null | | validate | The validation to use on the input value. When set to true, the validators will be recognized automatically based on the type and required properties. | boolean | array | function | string | false = No validationtrue = The validators will be recognized based on the type property.(value) => String(value).startsWith('ez')"max:255""between:10,20"[{type: 'custom', assert: (value) => !value, message: () => 'Custom message!'}, 'max:10', {type: 'between', arguments: [10, 20]}] | false | | hideValidateMessage | Whether to hide the validation message or not | boolean | false | true | false | | format | The formatting to use on the input value. When set to true, the formatters will be recognized based on the type and validate properties. | boolean | string | function | array | false = No formattingtrue = The formatters will be recognized based on the type and validate properties.(value) => String(value).replace('a', 'b')"max:255""alphanumeric""regex_discard:/[0-9]/"['max:255', 'alphanumeric', {type: 'regex_discard', arguments: ['/0-9/']}] | false | | process | The processing to use on the input value. When set to true, the processing will be based on the type property. | boolean | function | false = No processingtrue = The processing is recognized based on the type property.(value) => parseFloat(value) | false | | required | Whether the field is required | boolean | false | true | false | | disabled | Whether the field is disabled. When set to true the input key will not be present in the submitted data | boolean | false | true | false | | onChange | The function to call when the change event occurs | function | (value) => console.log(`Value changed to ${value}`) | null | | onValidate | The function to call when the validation event occurs | function | (failedValidators) => console.log(failedValidators) | null |

Basic Inputs

These inputs were created to supply what the native <input> elements have to offer.
List of available basic inputs:

  • TextInput
  • NumberInput
  • EmailInput
  • PasswordInput

Example usage:

import Form, {TextInput, NumberInput, EmailInput, PasswordInput} from 'react-superior-forms';

const form = <Form
    route="/example"
    inputDefaults={{format: true, validate: true, process: true}}
>
    <label>Username:</label>
    <TextInput name="username" defaultValue="gordo"/>

    <label>Number:</label>
    <NumberInput name="favourite_number" defaultValue={123}/>

    <label>Email:</label>
    <EmailInput name="email" defaultValue="[email protected]"/>

    <label>Password:</label>
    <PasswordInput name="password"/>
</Form>;

3.3. InputGroup

The <InputGroup/> helps you group your input values.
The <InputGroup/> will wrap all <Input/>, <InputGroup/> and <InputGroupRepeater/> components.
It both stands as a wrapper component with helpful modifier classes such as --invalid — and as a way to group your key, value pairs into a parent key.

Example usage:

import Form, {InputGroup, TextInput, NumberInput} from 'react-superior-forms';

<Form route="/create/user" json={true}>
    <InputGroup name="user">
        <label>Username</label>
        <TextInput name="name"/>
    </InputGroup>
    <InputGroup name="user_preferences">
        <label>Favourite Number</label>
        <NumberInput name="favourite_number"/>
    </InputGroup>
</Form>;

Example output:

<form class="rsf-form">
    <fieldset class="rsf-input-group input-group-name-user">
        <label>Username</label>
        <input class="rsf-input rsf-input-type-text" name="name" type="text">
    </fieldset>
    ...
</form>

Parameters:

| Parameter | Description | Type | Example value(s) | Default | | - | - | - | - | - | | legend | The element or string to insert for the <legend/> of the <fieldset/>. | string | JSX | "My group"<span>My <b>fancy</b> group!</span> | null | | className | The classname to append to the list of classes. | string | "my-group" | null | | name | The key to group the values into | string | "users" | null | | defaultValue | The initial values for the entries placed in the group. Does not overwrite the defaultValue props of children inputs if there is any | array | {username: "edward_baldwin", favourite_number: 10, ...} | null | | before | The element to display before the <fieldset/> element | JSX | <h1>Buzz!</h1> | null | | after | The element to display after the <fieldset/> element | JSX | <h1>Buzz again!</h1> | null | | beforeInputs | The element to display before the inputs, in the <fieldset/> element | JSX | <h1>Buzz!</h1> | null | | afterInputs | The element to display after the inputs, in the <fieldset/> element | JSX | <h1>Buzz again!</h1> | null |

3.4. InputGroupRepeater

The <InputGroupRepeater/> helps you repeat certain groups of input values.
The <InputGroupRepeater/> wraps its children into one or multiple <InputGroup/> components depending on the entry count.
It also comes with a default add button to add new entries, and a remove button to remove the current entries one by one.

Example usage:

<Form route="/create/users">
    <InputGroupRepeater name="users" entries={1} minEntries={1} maxEntries={5}>
        <label>Username</label>
        <TextInput name="name"/>
        <label>Favourite Number</label>
        <NumberInput name="favourite_number" validate={true} format={true} process={true}/>
    </InputGroupRepeater>
</Form>;

Example output:

<form class="rsf-form">
    <fieldset class="input-group-repeater input-group-repeater-name-users">
        <div class="rsf-input-group-repeater-entry">
            <span>
                <fieldset class="rsf-input-group input-group-name-users">
                    <label>Username</label>
                    <input class="rsf-input rsf-input-type-text" name="name" type="text" value="">
                    ...    
                </fieldset>
            </span>
            <button class="rsf-...-button-remove" .../>
        </div>
        ...
        repeated entries
        ...
        <button class="rsf-...-button-add" .../>
    </fieldset>
</form>

Example visuals:

Repeater example

Parameters

| Parameter | Description | Type | Example value(s) | Default | | - | - | - | - | - | | legend | The legend to display for each repeated entries' <fieldset/> element. | string | function | "User" = will result in "User 1", "User 2"(props) => <span>My <b>{props.index}.</b> User</span> | null | | defaultValue | The initial values for the entries placed in the repeater. Does not overwrite the defaultValue props of children inputs if there is any | array | [{username: "edward_baldwin", favourite_number: 10, ...}, ...] | null | | entries | The initial amount of entries to display | number | 3 | 0 | | minEntries | The minimum amount of entries to display | number | 1 | 0 | | maxEntries | The maximum amount of entries to display | number | 5 | 0 | | addComponent | The component used for the button that is responsible for inserting a new entry | JSX | <button>Add new!</button> | The default add component | | removeComponent | The component used for the button that is responsible for removing an entry | JSX | <button>Remove this!</button> | The default remove component |

3.5. SubmitButton

The <SubmitButton/> is used as the button that fires the onSubmit event of the <Form/>.
It acts as the native <button type="submit"></button> or <input type="submit"/> element.

Example usage:

import Form, {SubmitButton} from 'react-superior-forms';

<Form route="/example">
    ...
    <SubmitButton/>
</Form>;

Example output:

<button class="rsf-submit-button" type="submit">Submit</button>

Parameters:

| Parameter | Description | Type | Example value(s) | Default | | - | - | - | - | - | | children | The children of the <button>...</button> element. | JSX | "Submit" | "Submit" |

3.6. SubmitStatus

The <SubmitButton/> is used to display the status text of the last submit attempt.

Example usage:

import Form, {SubmitStatus} from 'react-superior-forms';

<Form route="/example">
    ...
    <SubmitStatus/>
</Form>;

Example output:

<span class="rsf-submit-status rsf-submit-status--fail">Failed to submit</span>

4. Builder API, <FormBuilder/>

The <FormBuilder/> is used to transform a JSON into a form.

Example usage:

import {FormBuilder, InputTypes} from 'react-superior-forms';

<FormBuilder
    route="/example"
    inputGroups={[
        {
            repeater: {
                entries: 1,
                legend: 'Entry',
            },
            legend: 'My group',
            className: 'my-group',
            name: 'users',
            inputs: [
                {
                    label: 'This users\'s username',
                    name: 'username',
                    type: InputTypes.Text,
                    wrapperClassName: 'my-wrapper',
                    className: 'my-input',
                    before: <h1>Hello world!</h1>,
                    defaultValue: 'test',
                    onChange: (value) => console.log(value),
                    onValidate: (validators) => console.log(validators),
                },
                {
                    name: 'email',
                    type: InputTypes.Email,
                    defaultValue: '[email protected]',
                    className: 'email-input',
                    validate: true,
                    format: true,
                    process: true,
                },
            ],
            inputGroups: [
                {
                    legend: 'My nested input group',
                    className: 'my-nested-group',
                    name: 'sub-users',
                    inputs: [
                        {
                            label: 'Username',
                            name: 'username',
                            type: InputTypes.Text,
                            className: 'my-input',
                        },
                    ],
                },
            ],
        },
    ]}
/>;

Parameter documentation coming soon.


Dependencies:

Other Links: