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

@ctrliq/quantic-components

v1.96.2

Published

Readme

Quantic components

Component manifest

The package publishes every documented component as static data at @ctrliq/quantic-components/meta.json, generated at build time from the static meta each component declares. It is plain JSON, with no runtime imports and no loader:

const manifest = require('@ctrliq/quantic-components/meta.json');
{
  "schemaVersion": 1,
  "generated": "2026-08-25T00:00:00.000Z",
  "components": [
    {
      "tag": "quantic-dialog",
      "description": "Modal overlay dialog with focus trap ...",
      "category": "feedback",
      "props": [
        {
          "name": "open",
          "description": "Whether the dialog is visible.",
          "type": "boolean",
          "default": "false"
        }
      ],
      "events": [{ "name": "after-close", "description": "Fired after the dialog closes ..." }],
      "slots": [{ "name": "trigger", "description": "Element that opens the dialog when clicked." }],
      "examples": ["<quantic-dialog> ... </quantic-dialog>"],
      "relatedTo": ["quantic-button"],
      "avoidWhen": [
        {
          "when": "the dialog only confirms a destructive action",
          "useInstead": "quantic-confirm-dialog"
        }
      ],
      "accessibility": {
        "providedByComponent": ["focus trap, restore on close, Escape to dismiss"],
        "requiredFromConsumer": ["a title, via quantic-dialog-title or aria-label"]
      },
      "subComponents": ["quantic-dialog-title", "quantic-dialog-actions"]
    }
  ]
}

Props, slots and events are arrays carrying their name, and empty fields are omitted. Nothing is filtered out: forwarded native events are included and flagged, so a consumer decides whether to care. Treat a missing meta.json as "this install predates the manifest" rather than an error.

The docs tier

meta.json is the whole manifest and too large to put in context, so the package also publishes a progressive-disclosure tier generated from it by scripts/gen-llms.ts:

| Export | What it is | | --- | --- | | @ctrliq/quantic-components/llms.txt | The index: how to install, and one line per component | | @ctrliq/quantic-components/llms/{category}-components.md | One file per category | | @ctrliq/quantic-components/llms/components/{tag}.md | one file per component, props, slots, events and examples |

Read the index, then the category, then the component. Every file resolves from node_modules at the version the project installed, so no network call is involved and no server can serve a version that disagrees with the installed package.

The index carries the install and wiring steps, extracted from the marked region of docs/getting-started.md rather than restated, because naming the components correctly is useless without knowing what to install and which stylesheets to load.

Storybook copies the same bytes into its public/ to serve them at /llms.txt, /llms/** and /components.json. The package is the producer; the app is a consumer.

Fields

Everything except tag, description and category is optional and omitted when unset, so a reader has to treat absence as "not stated" rather than as a default.

| Field | Type | What it carries | | --- | --- | --- | | tag | string | The custom element name. The React wrapper name is its pascal case. | | description | string | One or more sentences. The first sentence alone is used in the generated indexes. | | category | enum | action, form, display, layout, feedback, navigation or data. | | props | array | Each with name, type, and optionally description, options, default, required, copyRule. | | slots | array | Each with name and description, and optionally required, copyRule. The default slot has name: "". | | events | array | Each with name, and optionally description, detail, forwarded. | | examples | string[] | Markup, extracted from the Storybook stories at build time rather than hand-written. | | relatedTo | string[] | Neighbouring tags. Says they are related, not which to choose. | | avoidWhen | array | When to reach for something else. Each entry has when, and useInstead when there is an alternative to name. useInstead holds a tag when the alternative is a component and prose when it is not, since the answer is sometimes a stylesheet. | | accessibility | object | providedByComponent is behaviour the component implements, so a consumer must not reimplement it. requiredFromConsumer is what it cannot supply for itself, such as an accessible name. | | ascii | string | Diagram of the component's anatomy. | | experimental | boolean | The API can change or be removed in a minor. Absence means supported. See rules/promotion.md. | | deprecated | object | use names the replacement, reason says why. | | subComponentOf | string | The parent this element is anatomy of, set only when the child is inert alone. | | subComponents | string[] | Derived from the children's subComponentOf, so the two can never disagree. |

Copy rules

A prop or slot that holds user-facing text carries copyRule, a reference into the lexicon the manifest ships as its top-level copyRules:

{
  "copyRules": {
    "action-label": {
      "rule": "Verb phrase naming what happens, specific enough to act on without the surrounding text.",
      "good": ["Delete project", "Restart node"],
      "avoid": ["OK", "Yes", "Submit", "Continue"]
    }
  },
  "components": [
    {
      "tag": "quantic-confirm-dialog",
      "props": [{ "name": "confirmText", "type": "string", "copyRule": "action-label" }]
    }
  ]
}

The reference is what keeps the rules consistent. The wording rule for a placeholder is the same on six inputs, so it is stated once and pointed at six times rather than copied and left to drift. Rules are named after the job the text does rather than the component that carries it, which is why one placeholder rule serves all of them.

Ids are typed as CopyRuleId in src/shared/copy-rules.ts, so a component referencing a rule that does not exist is a compile error rather than a dangling pointer in the published data. A reader resolving an id it cannot find should say nothing rather than print the id.

copyRule is set only where getting the wording wrong is a real failure, which is labels, headings, messages and placeholders. Most props do not carry one. An ariaLabel prop never does: an accessible name is an accessibility requirement, so it belongs in accessibility.requiredFromConsumer.

Versioning

schemaVersion is bumped when an existing reader could break: a field removed or renamed, a type changed, or a meaning changed. Adding an optional field does not bump it, because a reader that ignores the field is unaffected, so tooling must tolerate keys it does not recognise rather than refusing the document. Refuse a schemaVersion you do not know.

Icons

Per-icon elements are registered with the rest of the library, so <quantic-icon-lucide-rocket> needs nothing beyond the package entry point:

import '@ctrliq/quantic-components/register';

@ctrliq/quantic-components/icons is the separate, opt-in entry for the name-based lookup, <quantic-icon name="Rocket">. It inlines every Lucide glyph so a runtime name can resolve, which is around 1 MB, and it is kept out of the package entry point for that reason. Prefer the per-icon element unless the name is genuinely only known at runtime.

Recommended tools

(lit-plugin)[https://marketplace.visualstudio.com/items?itemName=runem.lit-plugin] (VS code)