React 19 · TypeScript · tree-shakeable
Lightweight, modular React libraries
PiplupJS is a set of small packages that each solve one problem well — React Hook Form adapters for MUI, role-based access control, cache busting — so you install what you need and nothing else.
Pick the problem
The packages are grouped by what they solve, not by what they are built from.
React Hook Form adapters
Bind react-hook-form to MUI, the X date pickers or native inputs without rewriting the same Controller boilerplate on every field.
- @piplup/rhf-core
- @piplup/rhf-adapters
Access control for React
Gate UI on the signed-in user’s roles and permissions, with hierarchical wildcard grants and permission names TypeScript checks for you.
- @piplup/react-acl
Cache busting for React and Vite
Notice that a new build has shipped and reload clients still running the old bundle, instead of leaving users on a stale release.
- @piplup/cache-buster
- @piplup/vite-plugin-cache-buster
React utility hooks
The ref helpers, stable callbacks and reactive localStorage hook the other packages are built on, published on their own.
- @piplup/utils
Wired up, not wrapped up
Field binding and validation come from the adapter. The permission check resolves wildcards. Neither needs a Controller or a context lookup in your component.
import { FormContainer } from '@piplup/rhf-core';import { MuiTextFieldElement } from '@piplup/rhf-adapters/mui-material';import { Can } from '@piplup/react-acl';export function InvoiceForm() { return ( <FormContainer onSuccess={save}> <MuiTextFieldElement name="reference" label="Reference" rules={{ required: 'Required' }} /> {/* Rendered only if the user holds invoice:write — or invoice:* */} <Can permission="invoice:write"> <Button type="submit">Save</Button> </Can> </FormContainer> );}Small on purpose
Each package covers one concern and ships ESM and CJS with `sideEffects: false`, so your bundler drops what you do not import.
Typed end to end
Types are generated from the source, not hand-maintained. Permission and role names can be narrowed to your own strings so a typo fails the build.
Adapters, not wrappers
Every adapter is a hook returning props and an element that spreads them. When the element does not fit, drop to the hook instead of forking it.
Peer-dependency honest
React, MUI and react-hook-form stay peers, so you control their versions and never end up with two copies in one app.
Start with the problem you have
Every package has an installation page with a runnable example, and the API pages are generated from the types they ship.