TypeScript icon, indicating that this package has built-in type declarations

1.6.0 • Public • Published

🙋‍♂️ Made by @koenbrouwer.

Welcome to react-grapple 👋


A collection of useful hooks that I made. This is a Node.js package available through the npm registry. You can install react-grapple with the npm install command.


npm install --save react-grapple



const [state, toggleState] = useToggle(); // defaults to false

You can also give it another default initial state:

const [state, toggleState] = useToggle(true); // defaults to true

If you don't give it a default value, it will default to false, or the boolean you feed it. Then, toggleState() will toggle the value from true to false, or false to true.


I was recently at a conference where the website would still sell tickets after the event had already ended. That's of course bad practice. It would be much better to show some video recordings from the event or maybe a list of upcoming events. So to automate this, you can use the useConditionalByTime hook. (If you know a better name for this hook, let me know @KoenBrouwer)

const [Before, After] = useConditionalByTime(date, realtime); // date is of type Date, realtime is a boolean

You can pass a Date object as the first argument. The hook then returns two new components in an array, which you can use to wrap your components to be displayed before the splitDate and after. Because of array destructuring, you can use your own names for those components, but for the sake of simplicity, we just used Before and After here.

You can pass true as the second argument if you want the hook to actively keep track of time and rerender realtime.

Here's an example for your awesome event landing page:

import React from "react";

const App: React.FC = () => {
    const eventStartDate = new Date("2020-04-30 14:00");
    const [Before, After] = useConditionalByTime(eventStartDate, true);

    return (
        <div className="App">
            <h1>React Live, Amsterdam 2020</h1>

                    Buy your tickets to this event now!

                <BuyTickets />
                    Wow, that was an awesome conference! Take a look at our schedule for next year!
                <Schedule />

So, everything inside <Before> will be rendered if the date is in the future, and everything inside <After> is rendered if the date is in the past. Because we've passed true as the second argument of the useConditionalByTime hook, the page gets rerendered automatically once the date passes.


Handling change events on input fields is always a tedious process. Not with the useInput hook and easy binding.

There are two ways of initializing the useInput hook. First way is to give it one argument of type string, which represents the default value of the input field. The input field that gets rendered will be prepopulated with this defaultValue.

const field = useInput(initialValue); // initial value is always a string.

You can also pass an object of options as an argument to useInput() that implements the UseInputOptions interface. This way, you can add validations rules to your field. Here's an example:

const field = useInput({
	defaultValue: "",
	validate: [Validators.required, Validators.password, Validators.mail]

There's currently some built-in validators, available from the Validators object:

  1. Validators.required - the field cannot be left empty or filled with spaces.
  2. - tests the field value agains a Regex pattern for email addresses.
  3. Validators.password - requires the field value to:
    • Contain at least 8 characters
    • Contain at least one uppercase letter (A-Z)
    • Contain at least one lowercase letter (a-z)
    • Contain at least one number (0-9)
    • Contain at least one number that is none of the above (special characters)

You can also add your own validator function that returns true or false:

const field = useInput({
	validate: [Validators.required, (value: string) => value === "whatever"]

ℹ️ For now, useInput only supports text inputs. I might add checkboxes, radios and selects in a future version, once I feel like I need them. If you wish to add them to the library yourself, feel free to open a pull request if you have a solution.

Anyway, just define the fields for your form like this:

const name = useInput("");
const city = useInput("");
const country = useInput("Netherlands");

Then bind the value and change handler to your input element like this:

<input type="text" {} /> -> <input type="text" value={name.value} onChange={name.onChange} ref={name.ref} />
<input type="text" {} /> -> <input type="text" value={city.value} onChange={city.onChange} ref={city.ref} />
<input type="text" {} /> -> <input type="text" value={country.value} onChange={country.onChange} ref={country.ref} />

On an <input>, bind will just pass a value and onChange to the input, and will handle changes for you. The useInput hook will also create a reference to every input field that is accessible via the ref property.

After binding, you can reference the value and ref of the input like this:

name.value // returns the value for this field
name.ref // holds the RefObject for this field

This ref comes in handy when you wish to talk to the input field directly, for example focus on the input:

const name = useInput("");

Some other useful properties and methods you can call on the result of useInput():

  • isValid will be true if all validation rules return true. Updates automatically using onChange.

Since v1.5.0 clear has been renamed to reset.

  • reset() sets the value of the field to "".
  • setValue() sets the value of the field to whatever you pass to it, if you ever need to set the value manually.
  • dirty indicates with a boolean if the field has changed since initial render.


This is basically an extension to useInput, but bind contains a couple more fields: min, max, step and type="number".

const nOrders = useNumberInput(1); // default value 1

You can also configure them in the options instead of passing a default value:

const nOrders = useNumberInput({
	defaultValue: 1,
	max: 10,
	min: 2,
	step: 0.1

Then bind to an input as usual:

<input {...nOrders.bind} />


This hook uses window.innerWidth to detect if the current viewport is "mobile" or not. It has a default breakpoint of 650px. You can also pass a custom breakpoint as the only argument. When the window resizes, isMobile updates.

const isMobile = useIsMobile(); // return true if window.innerWidth < 650
const isMobile = useIsMobile(450); // return true if window.innerWidth < 450


Same as useIsMobile, execpt that isMobile it doesn't update when the window resizes.


👤 Koen Brouwer

🤝 Contributing

Feel free open an issue on the issues page or a pull request in the repo on GitHub!

Show your support

Give a ⭐️ if this project helped you!



Contributions, issues and feature requests are welcome!



Package Sidebar


npm i react-grapple

Weekly Downloads






Unpacked Size

93.2 kB

Total Files


Last publish


  • koenbrouwer