A minimal devtools implementation for React Hook Form built using TanStack DevTools
npm install @nourkodra/react-hook-form-devtoolsA minimal devtools implementation for React Hook Form built using TanStack DevTools.
- Real-time Form State Monitoring: View form values, errors, and state in real-time
- Form Validation Tracking: See which fields are dirty, touched, valid, or invalid
- Multiple Forms Support: Register and monitor multiple forms simultaneously
- Extensible Architecture: Easy to extend with additional functionality
- Zero External Styling Dependencies: All styles are inline, no CSS imports needed
- Collapsible Sections: Keep your devtools organized with collapsible sections
``bash`
npm install @kodraa/react-hook-form-devtoolsor
yarn add @kodraa/react-hook-form-devtoolsor
pnpm add @kodraa/react-hook-form-devtoolsor
bun add @kodraa/react-hook-form-devtools
Make sure you have the following installed:
`bash`
npm install react react-dom react-hook-form @tanstack/react-devtools
`tsx
import { TanStackDevtools } from "@tanstack/react-devtools";
import { RHFDevtoolsPanel } from "@kodraa/react-hook-form-devtools";
function App() {
return (
<>
{/ Your app content /}
plugins={[
{
name: "React Hook Form",
render:
},
]}
/>
>
);
}
`
`tsx
import { useForm, FormProvider } from "react-hook-form";
import { RHFDevtools } from "@kodraa/react-hook-form-devtools";
function MyForm() {
const form = useForm({
defaultValues: {
username: "",
email: "",
},
});
return (
);
}
`
Component to register a React Hook Form instance with the devtools.
Props:
- formId - A unique identifier for the form (string)
Example:
`tsx
import { FormProvider } from "react-hook-form";
import { RHFDevtools } from "react-hook-form-devtools";
const form = useForm();
return (
{/ Your form content /}
);
`
React component that renders the devtools panel UI.
Event client for managing form registration and accessing form methods.
Methods:
- registerForm(formId, formMethods) - Register a form and emit registration event (automatically called by RHFDevtools)unregisterForm(formId)
- - Unregister a form and emit unregistration eventgetFormMethods(formId)
- - Get form methods for a specific formgetAllForms()
- - Get all registered forms (returns Array)getRegisteredFormIds()
- - Get all registered form IDson(event, handler)
- - Subscribe to devtools events (register-form, unregister-form)emit(event, payload)
- - Emit an event to the devtools
Accessing Form Methods:
Form methods are stored directly in the client (not serialized through events) and can be accessed anytime:
`tsx
import { DevtoolsEventClient } from "react-hook-form-devtools";
// Get form methods for any registered form
const formMethods = DevtoolsEventClient.getFormMethods("my-form-id");
if (formMethods) {
// Access all React Hook Form methods
formMethods.reset(); // Reset the form
formMethods.setValue("fieldName", "newValue"); // Set a field value
formMethods.trigger(); // Trigger validation
// Access form state directly
const values = formMethods.getValues();
const errors = formMethods.formState.errors;
}
`
Events:
- register-form - Emitted when a form is registered (payload: { formId: string })unregister-form
- - Emitted when a form is unregistered (payload: { formId: string })
The devtools architecture is designed to be extensible. Here are some ways you can extend it:
Subscribe to form registration/unregistration events:
`typescript
import { DevtoolsEventClient } from "react-hook-form-devtools";
// Listen for when forms are registered
DevtoolsEventClient.on("register-form", (event) => {
console.log("Form registered:", event.payload.formId);
const formMethods = DevtoolsEventClient.getFormMethods(event.payload.formId);
});
// Listen for when forms are unregistered
DevtoolsEventClient.on("unregister-form", (event) => {
console.log("Form unregistered:", event.payload.formId);
});
`
Extend the EventMap type in eventClient.ts to add your own events:
`typescript`
type EventMap = {
"rhf-devtools:register-form": { formId: string };
"rhf-devtools:unregister-form": { formId: string };
"rhf-devtools:custom-event": { data: any }; // Add your custom event
};
You can add buttons or controls in the DevTools panel that interact with forms using the stored form methods:
`tsx
// In your DevtoolsPanel component
const formMethods = DevtoolsEventClient.getFormMethods(selectedFormId);
// Add buttons for common actions
`
Modify DevtoolsPanel.tsx to add additional UI elements, tabs, or visualizations. The panel has direct access to all form methods through DevtoolsEventClient.getFormMethods(formId).
The devtools uses a simplified architecture that combines TanStack's event system with direct form method access:
1. Event Client (eventClient.ts):
- Stores form methods in a Map (bypassing serialization issues)
- Uses TanStack's event bus only for registration/unregistration notifications
- Provides direct access to form methods via getFormMethods()
2. DevTools Component (rhf-devtools.ts):
- Registers forms with the event client on mount
- Unregisters forms on unmount
- Simple and lightweight
3. DevTools Panel (DevtoolsPanel.tsx):register-form
- Listens to and unregister-form events to track available formsgetFormMethods()
- Accesses form state directly through watch()` for reactivity
- Subscribes to form changes using React Hook Form's
Some ideas for extending the devtools:
- Time-travel debugging: Record and replay form state changes
- Field-level history: Track individual field value changes over time
- Performance metrics: Monitor render counts and re-renders
- Form validation testing: Test validation rules directly in the devtools
- State snapshots: Save and restore form states