npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

overkit

v0.0.5

Published

Simplified overlay management system for React

Downloads

404

Readme

Overkit

Simplified overlay management system for React and Next.js. Uses Zustand for state management and allows creating modals, drawers, sheets, and more with ease.

Features

  • Centralized State: State management with Zustand
  • Simple Triggers: Open overlays with a single click
  • Portals: Flexible rendering with tunnel-rat
  • TypeScript: Complete and safe typing
  • Dynamic Configuration: Props based on store state
  • Built-in Hooks: Access state from any component

Installation

npm install overkit
# or
yarn add overkit
# or
pnpm add overkit

Basic Usage

1. Create a Registry

First, create a base component that will serve as the overlay (Modal, Drawer, Sheet, etc.):

// components/modal.tsx
import { registry, type RegistryComponentProps } from "overkit";

const Modal = ({
  open,
  onOpenChange,
  title,
  description,
  t,
  children,
}: RegistryComponentProps) => {
  if (!open) return null;

  return (
    <div className="modal-backdrop" onClick={() => onOpenChange?.(false)}>
      <div className="modal-content">
        <h2>{title}</h2>
        <p>{description}</p>
        {children}
        <t.Out /> {/* Portal outlet */}
      </div>
    </div>
  );
};

export const ModalRegistry = registry({
  name: "modal",
  render: Modal,
});

2. Configure Overkit

// overlays.tsx
import { Overkit } from "overkit";
import { ModalRegistry } from "./modal";

const o = new Overkit(["userModal", "confirmDialog"] as const)
  .with(ModalRegistry)
  .build();

// Create simple overlay
const userDialog = o.create("userModal", "modal").configure({
  title: "User Profile",
  description: "Manage your profile information",
});

// Create overlay with extended state
const confirmDialog = o
  .create("confirmDialog", "modal")
  .extend<{ message: string }>(() => ({
    message: "",
  }))
  .configure({
    title: "Confirm Action",
    description: "Are you sure?",
  });

// Export components
export const UserModalTrigger = userDialog.trigger;
export const UserModalView = userDialog.view;

export const ConfirmTrigger = confirmDialog.trigger;
export const ConfirmView = confirmDialog.view;
export const useOverkitStore = o.useOverkitStore;

3. Use in Your App

// page.tsx
import { UserModalTrigger, UserModalView } from "./overlays";

export default function Page() {
  return (
    <div>
      <UserModalTrigger>
        <button>Open User Modal</button>
      </UserModalTrigger>

      <UserModalView />
    </div>
  );
}

API

Overkit

The main class for creating and managing overlays.

const o = new Overkit(["key1", "key2"] as const).with(RegistryItem).build();

.create(key, registryName)

Creates a new overlay.

const dialog = o.create("myDialog", "modal");

.extend<State>(storeCreator)

Extends the overlay state with additional properties.

const dialog = o
  .create("myDialog", "modal")
  .extend<{ count: number }>((set) => ({
    count: 0,
    increment: () => set((state) => ({ count: state.count + 1 })),
  }));

.configure(options)

Configures the overlay properties. You can use static values or functions that receive the store:

const dialog = o
  .create("productDialog", "modal")
  .extend<{ mode: "create" | "edit" }>((set) => ({
    mode: "create",
    setMode: (mode) => set({ mode }),
  }))
  .configure({
    // Static values
    title: "Product",

    // Functions with store access
    title: (store) =>
      store?.mode === "create" ? "Create Product" : "Edit Product",
    description: (store) =>
      store?.mode === "create"
        ? "Create a new product"
        : "Edit existing product",
    className: (store) =>
      store?.mode === "create" ? "mode-create" : "mode-edit",
  });

trigger

Component to open the overlay.

<Trigger>
  <button>Open</button>
</Trigger>

// With initial store values
<Trigger count={100}>
  <button>Open with 100</button>
</Trigger>

// With componentProps for the view
<Trigger componentProps={{ items: ["a", "b", "c"] }}>
  <button>Open with Items</button>
</Trigger>

view

Component that renders the overlay content.

// Basic
const View = dialog.view(() => <div>Content</div>);

// With props
const View = dialog.view<{ items: string[] }>(({ items }) => (
  <ul>
    {items.map((item) => (
      <li key={item}>{item}</li>
    ))}
  </ul>
));

// With close function
const View = dialog.view(({ close }) => (
  <div>
    <button onClick={close}>Close</button>
  </div>
));

// With useInnerContext (requires .extend())
const View = dialog.view(({ useInnerContext }) => {
  const count = useInnerContext((state) => state.count);
  const increment = useInnerContext((state) => state.increment);

  return (
    <div>
      <p>Count: {count}</p>
      <button onClick={increment}>Increment</button>
    </div>
  );
});

// With In portal component
const View = dialog.view(({ close, In }) => (
  <div>
    <p>Main content here</p>
    <In>
      {/* This content will be rendered where t.Out is placed in the registry */}
      <div className="footer">
        <button onClick={close}>Cancel</button>
        <button onClick={close}>Confirm</button>
      </div>
    </In>
  </div>
));

useOverkitStore

Hook to access the global state of all overlays.

const isOpen = useOverkitStore((state) => state.states.myDialog);
const setOpen = useOverkitStore((state) => state.setMyDialog);

// Open/close programmatically
setOpen(true);
setOpen(false);

Advanced Examples

Portals (tunnel-rat)

Overkit uses tunnel-rat to enable flexible rendering. You can render content in one part of your view and have it appear elsewhere in your overlay (e.g., buttons in a modal footer).

1. Update your registry component to include t.Out:

const Modal = ({
  open,
  onOpenChange,
  title,
  description,
  t,
  children,
}: RegistryComponentProps) => {
  if (!open) return null;

  return (
    <div className="modal-backdrop">
      <div className="modal-content">
        <h2>{title}</h2>
        <p>{description}</p>
        {children}
        <div className="modal-footer">
          <t.Out /> {/* Portal outlet - content from <In> appears here */}
        </div>
      </div>
    </div>
  );
};

2. Use In in your view to portal content:

const dialog = o.create("confirmDialog", "modal").configure({
  title: "Confirm Action",
  description: "Are you sure you want to proceed?",
});

const ConfirmView = dialog.view(({ close, In }) => (
  <div>
    <p>This content appears in the main modal body.</p>

    <In>
      {/* This content will be portaled to t.Out location */}
      <button onClick={close} className="btn-secondary">
        Cancel
      </button>
      <button onClick={close} className="btn-primary">
        Confirm
      </button>
    </In>
  </div>
));

Product Sheet (Create/Edit)

const productSheet = o
  .create("productSheet", "Sheet")
  .extend<ProductState>((set) => ({
    mode: "create",
    setMode: (mode) => set({ mode }),
  }))
  .configure({
    title: (store) => {
      return store?.mode === "create" ? "Create a Product" : "Edit Product";
    },
    description: (store) => {
      return store?.mode === "create"
        ? "Fill in the details of the product you want to create"
        : "Fill in the details of the product you want to edit";
    },
    className: "!max-w-none w-3/8",
  });

Counter with Extended State

const counterDialog = o
  .create("counter", "modal")
  .extend<{ count: number }>((set) => ({
    count: 0,
  }))
  .configure({
    title: "Counter Dialog",
  });

// Open with initial value
<counterDialog.trigger count={100}>
  <button>Open with 100</button>
</counterDialog.trigger>;

// Use in the view
const CounterView = counterDialog.view(({ useInnerContext }) => {
  const count = useInnerContext((state) => state.count);
  return <div>Count: {count}</div>;
});

TypeScript

Overkit is fully typed. When creating overlays, types are automatically inferred:

// Keys are validated at compile time
const o = new Overkit(["dialog1", "dialog2"] as const);

// TypeScript knows only "dialog1" and "dialog2" are valid
o.create("dialog1", "modal"); // ✅
o.create("dialog3", "modal"); // ❌ Type error

License

MIT