- ✅ Utilize the full controll of
CustomEvents
with a custom API - ✅ End-to-end type safety; validate event payload at runtime via your provided
Zod
schema - ✅ Framework agnostic; runs on any
JavaScript
environment - ✅ Supports all
CustomEvent
native properties and methods inherited by theEvent
interface - ✅ Middleware support for event processing
- ✅ Less than 1kb minified and gzipped
Install zod-custom-events using your favorite package manager or CDN, then include it in your project:
# Install with npm
npm install zod-custom-events
# Install with pnpm
pnpm add zod-custom-events
# Install with yarn
yarn add zod-custom-events
# Install with bun
bun add zod-custom-events
# Install in a node project
npx jsr add @georgecht/zod-custom-events
# Install in a deno project
deno add jsr:@georgecht/zod-custom-events
# Install in a bun project
bunx jsr add @georgecht/zod-custom-events
<!-- Via jsdelivr -->
<script src="https://cdn.jsdelivr.net/npm/zod-custom-events@latest/dist/index.min.js"></script>
<!-- Via unpkg -->
<script src="https://www.unpkg.com/zod-custom-events/dist/index.min.js"></script>
Here's a basic example of how to use zod-custom-events:
import { z } from 'zod';
import { EventController } from 'zod-custom-events';
// Define your event schema
const userSchema = z.object({
id: z.number(),
email: z.email(),
});
// Create an event controller
const userEventController = new EventController(userSchema, 'user-event');
// Subscribe to the event
userEventController.subscribe((event) => {
console.log('Received user event:', event.detail);
});
// Dispatch an event
userEventController.dispatch({
id: 123,
email: '[email protected]',
});
// Cleanup
userEventController.unsubscribe();
The API reference is available on GitHub.
The main class for managing custom events. The EventController<T extends ZodSchema>
extends the CustomEvent
interface with a detail
property of type T
. Meaning it will match the CustomEvent
interface and infer all the functionality.
constructor(schema: T, eventName: string, options?: EventControllerOptions<T>)
Creates a new EventController
instance.
schema
- The Zod schema for validating the event payload.eventName
- The name of the custom event.options
optional - Configuration options for theEventController
.
import { z } from 'zod';
import { EventController } from 'zod-custom-events';
const schema = z.object({
name: z.string(),
});
const controller = new EventController(schema, 'myEvent', {
onError: ({ error }) => console.error('Validation error:', error),
onDispatch: ({ payload }) => console.log('Dispatching event with payload:', payload),
});
element
optional - The element to bind the event to. Defaults towindow
.onError
optional - Error handler for validation errors.onDispatch
optional - Callback function called before dispatching the event.onSubscribe
optional - Callback function called when the event listener is added.onUnsubscribe
optional - Callback function called when the event listener is removed.
Subscribe to the event.
subscribe(listener: (event: TypedCustomEvent<EventPayload<T>>) => void, options?: AddEventListenerOptions): void
listener
- The function to be called when the event is triggered.options
- Optional parameters for the event listener.
once
optional - A boolean value indicating that thelistener
should be invoked at mostonce
after being added. Iftrue
, thelistener
would be automatically removed when invoked.passive
optional - A boolean indicating whether the event listener is apassive
listener. If set totrue
, indicates that the function specified by listener will never callpreventDefault()
. If a passive listener callspreventDefault()
, nothing will happen and a console warning may be generated.signal
optional - AnAbortSignal
to signal when the listener should be removed.
controller.subscribe((event) => {
console.log('Received user event:', event.detail);
});
// With abort signal and once option
const abortController = new AbortController();
const { signal } = abortController;
controller.subscribe((event) => {
console.log('Received user event:', event.detail);
}, { signal, once: true });
// Later in the code
abortController.abort();
Removes the previously registered event listener for the event.
unsubscribe(options?: EventListenerOptions): void
options
optional - Optional parameters to match the event listener.
capture
optional - A boolean value indicating that events of this type will be dispatched to the registeredlistener
before being dispatched to anyEventTarget
beneath it in the DOM tree.
controller.unsubscribe();
Dispatches the event, validating its payload using the Zod schema and applying middleware.
dispatch(payload: EventPayload<T>, eventInitDict?: CustomEventInit<EventPayload<T>>): Promise<void>
payload
- The data associated with the event. Validated against theZod
schema initially provided.eventInitDict
optional - Optional parameters for initializing the event.
bubbles
optional - A boolean value indicating whether or not the event can bubble through the DOM.cancelable
optional - A boolean value indicating whether the event can be cancelled.composed
optional - A boolean value indicating whether the event will trigger listeners outside of a shadow root (seeEvent.composed
for more details).
controller.dispatch({
id: 1,
name: 'John Doe',
}, {
bubbles: true
});
Sets a condition for the event, allowing control over whether the event is dispatched.
refine(condition: (payload: EventPayload<T>) => boolean, callback?: (ctx: EventPayloadContext<T>) => void): void
condition
- A function that takes the event payload as input and returns a boolean.callback
optional - An optional callback function to be called when the condition is not met.
controller.refine(
(payload) => payload.id > 0,
(ctx) => {
const { payload } = ctx;
console.log("Invalid user ID:", payload.id)
}
);
Updates the EventController
options.
update(options: Partial<EventControllerOptions<T>>): void
options
optional - New configuration options for theEventController
.
const controller = new EventController(schema, 'myEvent');
// Later in the code
controller.update({
onError: ({ error }) => console.warn('New error handler:', error),
onDispatch: ({ payload }) => console.log('New dispatch handler:', payload),
});
Adds a middleware function to the event processing pipeline.
use(middleware: Middleware<EventPayload<T>>): void
middleware
- A function that processes the event context and calls the next middleware.
controller.use(async (ctx, next) => {
console.log("Processing user event:", ctx.payload);
await next();
});
Contributions are welcome! Please open an issue or submit a pull request.
This project is licensed under the MIT License. See the LICENSE file for more details.