react-event-modifiers
v1.0.1
Published
Enhances React elements with Svelte-inspired event modifiers like 'onClick-preventDefault' and 'onClick-stopPropagation'.
Downloads
4
Maintainers
Readme
React Event Modifier
Enhances React elements with Svelte-inspired event modifiers.
📖 Overview
Svelte has a nice feature to modify events in useful ways. For example you can quickly call stopPropagation()
or preventDefault()
on your events with simple 'modifiers' on an element.
This library brings some of that functionality to React in a tiny ~1kB package.
How Svelte does it
<button on:click|stopPropagation="{handleClick}">
<!-- The click event wont't propagate -->
</button>
<form on:submit|preventDefault="{handleSubmit}">
<!-- The submit event won't reload the page -->
</form>
How react-event-modifiers
does it
import mod from "react-event-modifiers"
<mod.button onClick-stopPropagation={handleClick}>
{/* The click event wont't propagate */}
</mod.button>
<mod.form onSubmit-preventDefault={handleSubmit}>
{/* The submit event won't reload the page */}
</mod.form>
🚀 Get started
Install the library:
npm i react-event-modifiers
When you have an element you wish to update like this:
<button onClick={handleClick}>Click me</button>
Then import the library and update the element as follows:
import mod from "react-event-modifiers"
<mod.button onClick-stopPropagation={handleClick}>Click me</mod.button>
Note the mod.
prefix to the element, and the -stopPropagation
modifier to the event handler prop.
You can use modifiers without a handler like this:
<mod.button onClick-stopPropagation>Click me</mod.button>
and chain modifiers together like this:
<mod.button onClick-preventDefault-stopPropagation={handleClick}>Click me</mod.button>
All native JSX elements are supported and this library should act as a drop in replacement which doesn't affect other props. Typescript is fully supported too!
Note that the only Svelte modifiers that are supported are stopPropagation
and preventDefault
. React already supports capture
events and other modifiers were deemed too niche to implement.
🧐 How it works
Part of the reason for building this little library was to see if this was possible.
It works as follows:
- Importing
react-event-modifier
returns a proxy object. - When you call
<mod.div ...>
the proxy is called with the keyword 'div' and all of the react props. - This library can then create a normal react 'div' element and modify the props in any way we like.
- Typescript is used to ensure that only native elements (like
div
) and event handlers (likeonClick
) are modifiable.
Modifying the props:
- The props are given as a simple JS object with keys/vals like
{ "onClick-stopPropagation": customHandler }
. - This library can then strip out the modifiers like
-stopPropagation
and wrap functions with an appropriate handler. - Finally the new handler is assigned to the default keyword and the result is a modified object like
{ "onClick": (e) => { e.stopPropagation(); customHandler(e) } }
Creating the types:
- One critical piece of this library is ensuring that React types are maintained when using the library. For example:
- The element
<mod.div>
should have all of the props and types of<div>
- The handler
<mod.div onClick-stopPropagation={...}>
should have the same signature asonClick={...}
- The element
- The library uses all features of the Creating types from types handbook guide importantly:
- Mapped types to copy and modify the original
JSX.IntrinsicElements
types into custom ones - Template literal types to modify event types like
onClick
toonClick-stopPropagation
- Mapped types to copy and modify the original
- Finally this library even has Typescript tests which cover important use cases. E.g. testing that non-modifiable props like
className
are not polluted with modifiers.
🤷 Is this actually useful?
It's a definitely a tiny quality of life feature but it comes in handy. It really shines when making games and modals where there are many overlaying clickable elements. Having a simple modifier can keep code clean and even save you from making your own click wrappers. It's also a nice feature if you're writing a lot of client-side forms.
💻 Development
Issues and PRs are welcome!
Useful commands:
- Run tests:
npm run tests
- Run linting etc:
npm run check
- Run the UI demo:
cd react-demo-ts/
thennpm run dev
- Build:
npm run build