DEV Community

Cover image for React Forms Made Easy with react-binden🚀
Kingkor Roy Tirtho
Kingkor Roy Tirtho

Posted on

React Forms Made Easy with react-binden🚀

Introducing React Binden 🎉🚀

A react form handling library which is actually easy

React Binden is inspired from Vue's v-bind directive & is extremely lightweight yet fast

Its,

  • Lightweight, Fast & Tree-shakable
  • has Out of the Box validation without any 3rd party library
  • optimizes both Hooks & Components to get the best of both worlds
  • offers custom curated collection of useful Regex for validation purposes
  • UI component library proof
  • can be integrated with any UI component library/framework without any 3rd party library
  • zero dependencies

Why created this?

React forms, no doubt can be a nightmare for any developer. It can be messy to create a simple Login form in React

One day, while using Vuejs for creating a medium.com clone, I encountered with Vue's v-bind directive. Which allows to bind a value of a field with a variable. In React, that's not possible as React supports only one-way data-binding. Just think, if it was available in React, it'd been a god sent gift but alas!. Don't be sad as we can mimic two-way data-binding in React with state-up-lifting. It means declaring the state of a child in the parent & then passing that down to child. Kind of like prop-drilling but in a managed manner. You shouldn't do more than 2 times of state-up-lifting as it'd make the UI slow leading to huge re-renders

So I experimentally tried mimicking v-bind for input & walla, it worked fine. I though it might cause performance issues & huge re-renders but surprisingly it didn't instead it's fast & fast as normal. Then, I decided finish writing the library

Another reason is simplicity. I found every form library having some kind of complexity even though, they were doing their best to simplify React Form handling experience. Custom schema for validation, spreading props in Fields, hooks that returns huge amount of objects which you've to manually handle etc. kind of made me really confused. I discovered that, every form library is either completely hook based or completely component render function based or provides both API. I never found a single one that utilizes both custom components & hooks together. So, in with React-Binden I tried closing that gap which will give the developer best of both world

Third & final reason is size. Current form libraries aren't lightweight except react-final-form. So making a decent form library which is lightweight and tree-shakable was React Binden's one of the main goals. BTW, it uses ESNext module system

How to use

React Binden is extremely easy to use. It has the simplest API for handling React Forms. It provides hooks & custom components

The most important ones are the useModel, Form & Input. Using these 3, you can complete most of the job. Now let's see how to use useModel

Using useModel

useModel is nothing but a simple hook that just declares some required states for a Input's model. It requires a default value which can be a number, string or an Array (applicable only for checkbox-group). And has an optional parameter that can be used pass all the validation prop of an Input

import { useModel } from 'react-binden';

/*---------------------------------------*/

const model = useModel('', {
        name: 'some-field',
        max: 20,
        min: [5, 'minimum 5'],
        maxLength: 20,
        minLength: 5,
        pattern: regex.email,
        required: true,
        validate: (_value, _touched) => true,
        'semantic-validation': true,
});

// all the states/properties
model.value;
model.error;
model.touched;
model.default;
model.validations;

// all the methods
model.setValue('Some value');
model.setError('Some Error');
model.setTouched(true);
Enter fullscreen mode Exit fullscreen mode

Learn more about useModel here

Using Form

Form is a typical form component as well as a context provider. It doesn't hold a huge amount of state for the field. Only keeps the state of submit, reset & if all field have don't have any error

You can use onSubmit prop to handle form submission just like a vanilla HTML form. And it supports all other form attributes

Example of a Form

<Form
    onSubmit={async (event, {reset, errors}, methods) => {
        try{
        // handling form submission
        }
        catch(e){
        // handle exceptions
        }
    }}
>
    {/*... other components*/}
</Form>
Enter fullscreen mode Exit fullscreen mode

More about Form can be found here

Using Input

Input is what acts like an input field. useModel's model have to be bind with this component's model prop. It takes all the validation props. Since React Binden follows HTML validation standards & semantic HTML form validation attributes, all the HTML input validation props is present. But instead of validating while submission, React Binden validates in real time. You can pass custom error message with those validation props

Validation props that are supported

  • minmax (for numeric values)
  • minLengthmaxLength (for string values)
  • pattern (through regex)
  • required
export function Example() {
    const user = useModel('');

    return (
        <Input
            model={user}
            maxLength={30}
            // passing a custom error msg using Tuples
            minLength={[5, 'Minimum 5 characters']}
            required
        />
    );
}
Enter fullscreen mode Exit fullscreen mode

Here's more about Input

Learn more about Validation here

Validating password & confirm password is a pain, right? This is where imprint-model comes handy. Pass the password model to this & the field will only match to that password field

Example of imprint-model:

const password = useModel('');
const confirmPassword = useModel('');

return (
    <Form onSubmit={handleSubmit}>
        <Input
            model={password}
            required
            pattern={regex.moderatePassword}
            placeholder="Password"
        />
        <Input
            model={confirmPassword}
            // passing the model that should be imprinted/followed
            imprint-model={password}
            required
            placeholder="Confirm Password"
        />

        <button type="submit">Sign Up</button>
    </Form>
);
Enter fullscreen mode Exit fullscreen mode

Might be thinking about integrating React Binden with an UI component library/framework. No worries. You can learn about it here

Input can be validated completely manually using the validate prop. As a companion, there is also a useValidatorChain hook which can be used for using multiple validation functions at once

Regex

React Binden also provides an useful list of Regular Expressions that can be used with Input's pattern prop. Suppose validating an email field. This can be done with regex

import { regex, useModel, Input } from 'react-binden';

export function Login() {
    const email = useModel('');

    return (
        {/*....Form & other component....*/}
        <Input
            type="email"
            model={email}
            // using `regex.email` for validating email
            pattern={[regex.email, 'Should be a valid email']}
            required
        />
        {/*....Form & other component....*/}
    );
}
Enter fullscreen mode Exit fullscreen mode

The list of available Regex can be found here

React Binden also supports Textarea, Select, Checkboxes & Radio Group. And the entire library is written with Typescript❤️ so don't worry about Typescript support

Conclusion

This is a short review & tutorial of React Binden. The full documentation is what you should be looking for. To learn about all the features of React Binden visit react-binden.netlify.app

React Binden is a completely new library & heavily inspired by other form libraries too. Those are an asset & Thanks❤️ to those library authors for their outstanding generosity for the OSS community

If you ever encounter any bug related to React Binden create an issue on Github

Have any ideas to improve react-binden? Why not Discuss?

Follow us on twitter/@krtirtho

Give a 🌟 on Github

Top comments (0)