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

@kurajs/ctrlk

v0.1.0

Published

Kura — ⌘K command palette: a headless, zero-dependency command/search menu with a built-in default renderer. Framework-agnostic (vanilla DOM); mirrors cmdk's model & accessibility without React.

Readme

@kurajs/ctrlk

A headless, zero-dependency ⌘K command palette with a built-in default renderer. Vanilla DOM — no React, no Preact, nothing. It mirrors cmdk's model and accessibility (dialog + combobox/listbox/option, aria-activedescendant, full keyboard) so it drops into any stack — including server-rendered sites with no client framework — and ships zero runtime bytes beyond itself.

Batteries-included

import { createCtrlk, mountCtrlk } from "@kurajs/ctrlk";

const ctrl = createCtrlk({
  // Async source: called (debounced, abortable) on every keystroke.
  search: async (query, signal) => {
    const res = await fetch(`/search.json?q=${encodeURIComponent(query)}`, { signal });
    const { hits } = await res.json();
    return hits.map((h) => ({
      id: h.slug + "#" + h.headingId,
      title: h.heading ?? h.title,
      description: `${h.section} › ${h.title}`, // breadcrumb path
      excerpt: h.text,
      group: h.section,
      icon: h.headingId ? "hash" : "page",
      href: `/docs/${h.slug}` + (h.headingId ? `#${h.headingId}` : ""),
    }));
  },
});

mountCtrlk(ctrl, {
  trigger: ".search-box",            // clicking this opens the palette
  tokensOf: (s) => s.query.split(/\s+/), // or the engine's matched terms, for exact highlight
});
// ⌘K / Ctrl+K and "/" now open it; ↑/↓ navigate, Enter opens, Esc closes.

Static command list

Omit search and pass items to get cmdk-style local fuzzy filtering:

const ctrl = createCtrlk({
  items: [
    { id: "new", title: "New file", group: "Actions", keywords: ["create"] },
    { id: "theme", title: "Toggle theme", group: "Actions" },
  ],
  onSelect: (item) => run(item.id),
});
mountCtrlk(ctrl);

Headless

createCtrlk is the whole state machine (no DOM): open/close/toggle, setQuery, move/setActive, select, and subscribe. Drive your own renderer from getState(), or render with your framework of choice — mountCtrlk is just the default one.

const ctrl = createCtrlk({ items });
const stop = ctrl.subscribe((state) => paint(state)); // { open, query, loading, items, groups, activeIndex, error }

Theming

The default renderer is styled entirely through --ctrlk-* CSS variables (light/dark out of the box). Theme it by setting them on .ctrlk-overlay — e.g. to inherit a host's tokens: .ctrlk-overlay { --ctrlk-accent: var(--accent); --ctrlk-bg: var(--surface); }. Pass renderItem to fully control row markup, or injectStyles: false to ship your own.

API

  • createCtrlk(options) → Ctrlk — headless controller. Options: search | items + filter, debounce, empty, loop (wrap arrow nav, default true), shouldFilter (static mode, default true), value (initial highlight), onSelect, onValueChange, onOpenChange. Controller methods: open/close/toggle, setQuery, move/setActive, setValue (by id), setItems (swap the static pool), select, subscribe, getState, destroy. State exposes a cmdk-style value (the active item id) alongside activeIndex.
  • mountCtrlk(ctrl, opts) → { destroy } — default DOM. Opts: trigger, hotkey, labels, tokensOf, renderItem, injectStyles, platform, ariaLabel, target.
  • platformHotkeyLabel()"⌘K" on macOS, "Ctrl K" elsewhere (for a trigger hint).
  • highlight(text, tokens) → segments for custom renderers.

Zero dependencies. Runs on Node, Bun, Deno, Cloudflare Workers (core), and every browser.