Skip to content

Add Zep.js to Utility section - #1163

Open
marsbos wants to merge 1 commit into
sorrycc:masterfrom
marsbos:master
Open

marsbos wants to merge 1 commit into
sorrycc:masterfrom
marsbos:master

Conversation

@marsbos

@marsbos marsbos commented Sep 19, 2026

Copy link
Copy Markdown

Checklist:

  • I've read and understood Contributing Guidelines.
  • I've added the new resource at the end of its section.
  • This resource is out there for a while, and actively maintained.
  • This resource is popular enough and has at least a few hundred stars on GitHub.

What is this addition about?

Zep.js is an ultra-lightweight (265 bytes) event pipeline library designed to streamline DOM event management.

Instead of writing repetitive boilerplate for event handling, it combines event listening, debouncing, and automatic cleanup into a single chainable pipeline.

Key features include:

  • AbortSignal integration: Native event listener lifecycle management鈥攚hen the signal aborts, the entire pipeline cleans itself up automatically to prevent memory leaks.

  • Built-in debouncing: Seamlessly throttle or debounce event execution directly within the pipeline flow.

  • Zero dependencies: Leverages modern browser primitives to keep execution overhead and bundle footprint to a bare minimum.

Why should it be included in this list?

  • Modern approach to event cleanup: Most utility libraries still require manual removeEventListener references. Zep.js embraces modern standards by building around AbortSignal, providing a far cleaner API for single-page applications and component lifecycles.

  • Extreme bundle efficiency: At only 265 bytes, it offers a full event-pipeline DX without adding weight to production builds鈥攊deal for developers prioritizing web performance and micro-libraries.

  • Solves a universal frontend issue: Managing debounced input/scroll handlers alongside proper cleanup is a common source of bugs; Zep.js resolves this with a robust, declarative pattern.

Examples:

const cleanup = zep(inputEl, "input", { signal })
  .use(
    map((e) => e.target.value.trim()),
    filter((query) => query.length > 2),
    debounce(300),
    latest((query, signal) => fetchSearch(query, signal)),
  )
  .on(render);

// Calling cleanup() or passing an AbortSignal tears down
// all listeners and pending timers automatically.
import { zep } from "@marsbos/zep";
import { take, filter } from "@marsbos/zep/helpers";

zep(document, "keydown")
  .use(
    filter((e) => e.key === "Escape"), // <= We only want to act on the Escape key
    take(1), // <= Stop and unsubscribe
  )
  .on(() => closeModal());
import { zep } from "@marsbos/zep";
import { throttle, map } from "@marsbos/zep/helpers";

zep(window, "resize")
  .use(
    throttle(200),
    map(() => ({ width: window.innerWidth, height: window.innerHeight })),
  )
  .on(({ width, height }) => {
    console.log(`Window resized to: ${width}x${height}`);
  });

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant