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

doticca-ui

v0.2.1

Published

Framework-agnostic, zero-dependency UI component suite (DateTimePicker, SelectPicker) with a shared overlay core, design tokens, and touch-first UX.

Downloads

338

Readme

doticca-ui

A small suite of production-grade, framework-agnostic UI components written in plain JavaScript — zero dependencies, no virtual DOM, and no build step required. It currently ships two components, both built on one shared core and themed entirely through CSS custom properties:

  • DateTimePicker — date, time, datetime, and range modes, with an iOS-style inertial wheel on touch devices.
  • SelectPicker — a native <select> replacement: single, multi, searchable, grouped, virtualized, and async.

Each component is a self-contained class you point at an existing <input> or <select>. The element is enhanced in place while still submitting normally inside a form. Desktop gets a popover; touch devices get a native-feeling bottom sheet automatically. Light/dark themes auto-detect via prefers-color-scheme.

Documentation

The documentation site is the landing page of this app. Run the dev server (below) and open http://localhost:3000.

The docs are authored as a static site under public/docs/ and served at the root / (and at /docs) via a rewrite in next.config.mjs. They cover:

  • Introduction, Getting started, and Architecture
  • Per-component references (DateTimePicker, SelectPicker) with live, interactive examples
  • Theming, Accessibility, and Form integration
  • Examples and a guide to extending the system

Every example on the docs site runs the real bundled library, so what you see is exactly what ships.

MCP server (for AI tools)

/mcp is a real Model Context Protocol server, so AI assistants (VS Code / Copilot, Cursor, Claude Desktop, LLM agents) can connect to it and answer "how do I use component X" questions without hallucinating. It speaks JSON-RPC over the Streamable HTTP transport via Vercel's mcp-handler.

All answers derive from a single source of truth — lib/mcp/registry.ts, which mirrors the real component DEFAULTS and the shared BaseComponent surface — so the docs never drift from the shipped components.

Connect a client

Point any MCP client at the deployed endpoint (Streamable HTTP):

{
  "servers": {
    "doticca-ui": { "url": "https://ui.doticca.com/mcp" }
  }
}

For stdio-only clients, bridge with mcp-remote:

{
  "doticca-ui": {
    "command": "npx",
    "args": ["-y", "mcp-remote", "https://ui.doticca.com/mcp"]
  }
}

Tools

| Tool | Description | | --- | --- | | list_components | List every component with taglines, modes, and features. | | get_component | Full description, use cases, key behaviors, mobile vs desktop. | | get_component_api | Options (type, default, allowed values), methods, events. | | get_component_examples | Runnable usage examples with code. | | search_docs | Ranked search across components, features, options, examples, theming. | | recommend_usage | Recommended config + code for a component and intent (e.g. multi-select). | | get_theming | Design-token theming system with light/dark values and overrides. |

Browsable REST mirror

The same data is also exposed as a plain JSON REST API (handy for quick curl checks or non-MCP crawlers):

| Endpoint | Description | | --- | --- | | GET /mcp/info | Discovery manifest: suite info, MCP tools, and REST endpoints. | | GET /mcp/components | List all components with summaries. | | GET /mcp/components/{name} | Full detail for one component. | | GET /mcp/components/{name}/api | Options, methods, and events. | | GET /mcp/components/{name}/examples | Usage examples with code. | | GET /mcp/search?q={query} | Scored search across the suite. | | GET /mcp/theming | Machine-readable design-token system. | | GET /mcp/usage?component={name}&intent={intent} | Recommended config + code for an intent. |

curl "https://ui.doticca.com/mcp/usage?component=SelectPicker&intent=multi-select"
# => { "recommended": { "multiple": true, "searchable": true, "clearable": true }, ... }

To add a future component, extend COMPONENTS in lib/mcp/registry.ts; every MCP tool and REST endpoint picks it up automatically.

Getting Started

Install dependencies and run the development server:

npm install
npm run dev
# or: yarn dev / pnpm dev

Open http://localhost:3000 to view the documentation and live demos.

Installation

npm install doticca-ui

The package ships three files in dist/:

| File | Field | Use | | --- | --- | --- | | doticca-ui.esm.js | module | ESM build for bundlers (Vite, webpack, Rollup, Next.js). | | doticca-ui.min.js | main | Minified IIFE for a plain <script> tag (global DoticcaUI). | | doticca-ui.css | style | Single combined stylesheet for the whole suite. |

Usage with a bundler (import)

import { DateTimePicker, SelectPicker } from "doticca-ui"
import "doticca-ui/css"

// DateTimePicker — enhances an existing <input>
new DateTimePicker("#date", {
  mode: "datetime",   // "date" | "time" | "datetime" | "range"
  use24Hour: false,
  minuteStep: 5,
  onChange: (value) => console.log(value),
})

// SelectPicker — replaces a native <select> (or empty placeholder element)
new SelectPicker("#country", {
  options: [
    { label: "United States", value: "us" },
    { label: "Canada", value: "ca" },
  ],
  searchable: true,
  clearable: true,
})

Usage in the browser (no build step)

<link rel="stylesheet" href="https://unpkg.com/doticca-ui/dist/doticca-ui.css" />
<script src="https://unpkg.com/doticca-ui/dist/doticca-ui.min.js"></script>

<input id="date" />
<select id="country"></select>

<script>
  const { DateTimePicker, SelectPicker } = DoticcaUI
  new DateTimePicker("#date", { mode: "date" })
  new SelectPicker("#country", { searchable: true })
</script>

Both components share the --dt-* CSS custom properties, so a single token set themes the entire suite, and light/dark auto-detects via prefers-color-scheme. See the Theming page in the docs for the full token reference.

API overview

Each component is new Component(target, options), where target is a CSS selector or element. Instances expose open(), close(), getValue(), setValue(v), setTheme(theme), and destroy(), and accept onChange / onOpen / onClose callbacks.

DateTimePicker — key options

| Option | Type | Default | Notes | | --- | --- | --- | --- | | mode | string | "date" | "date", "time", "datetime", or "range". | | use24Hour | boolean | true | 24-hour vs 12-hour clock. | | minuteStep / hourStep | number | 1 | Step granularity for time wheels. | | minDate / maxDate | Date | null | Selectable bounds. | | disabledDates | array | fn | null | Date[], "YYYY-MM-DD"[], or (date) => boolean. | | displayFormat | string | null | e.g. "DD/MM/YYYY hh:mm A". | | inline | boolean | false | Render inline instead of in an overlay. | | touchUi | string | "auto" | "auto", true, or false (wheel bottom-sheet). | | theme | string | "auto" | "auto", "light", or "dark". |

SelectPicker — key options

| Option | Type | Default | Notes | | --- | --- | --- | --- | | options | array | null | { label, value }[], optionally grouped. Plain business objects also work — see columns. | | multiple | boolean | false | Multi-select with chips. | | searchable | boolean | false | Inline search filter. | | clearable | boolean | false | Show a clear control. | | maxSelections | number | Infinity | Cap for multi-select. | | virtualized | boolean | true | Virtualize long lists. | | loadOptions | fn | null | Async loader (query) => Promise<options>. | | placeholder | string | "Select…" | Empty-state text. | | theme | string | "auto" | "auto", "light", or "dark". | | columns | array | null | Rich column config (see below). Controls the visible grid layout and which fields are searchable. | | groupBy | fn | null | (item) => string — derive group headers from a flat option list. | | searchFields | string[] | null | Raw-object keys to include in search matching (even if not visible). | | getSearchText | fn | null | (item) => string — highest-priority custom search haystack. | | getDisplayValue | fn | null | (item) => string — text shown in the selected control. | | renderItem | fn | null | (item) => Node\|string — full custom row body (alias: renderOption). | | getAriaLabel | fn | null | (item) => string — custom per-option aria-label. |

SelectPicker — rich multi-column dropdowns

Each option can carry many fields — some visible as columns, some searchable-only. This powers business dropdowns like a supplier picker where the VAT/tax ID is searchable but not displayed.

Column config:

| Column key | Type | Notes | | --- | --- | --- | | key | string | Property read from the option object. | | label | string | Header label (reserved for future header UI). | | visible | boolean | false hides the column from the row but keeps it available for search. | | searchable | boolean | Include this field in search matching. | | width | string | CSS grid track size for the column (e.g. "1fr", "120px"). | | align | string | "left", "center", or "right". | | renderCell | fn | (value, item) => Node\|string — custom cell content. Strings are inserted as text (never HTML). |

Search source priority: getSearchTextsearchFields → searchable columns → the option label/value. Numeric queries also match digits-only (so "6969" matches a VAT formatted "69-69-69").

new SelectPicker("#supplier", {
  options: suppliers, // [{ id, name, vatNumber, balance, type }, ...]
  searchable: true,
  groupBy: (item) => item.name.charAt(0).toUpperCase(),
  searchFields: ["name", "vatNumber"], // VAT searchable but hidden
  getDisplayValue: (item) => item.name, // selected control shows only the name
  columns: [
    { key: "name", label: "Name", visible: true, searchable: true, width: "1fr" },
    { key: "vatNumber", label: "VAT", visible: false, searchable: true },
    {
      key: "balance",
      label: "Balance",
      visible: true,
      align: "right",
      width: "120px",
      renderCell: (value) => {
        const el = document.createElement("span")
        el.className = value > 0 ? "dt-positive" : value < 0 ? "dt-negative" : "dt-muted"
        el.textContent = new Intl.NumberFormat("el-GR", { style: "currency", currency: "EUR" }).format(value)
        return el
      },
    },
  ],
})

renderItem stays fully supported and takes over the entire row body; when provided, columns is used only for searchFields/search config and does not override your custom row. All existing features — grouping, multi-select, virtualization, async loadOptions, and keyboard navigation — continue to work with rich columns.

The full, machine-readable API (every option, method, and event) is available from the docs site and the MCP server.

Building from source

The component source lives in src/. Rebuild the dist/ bundles with:

npm run build:lib

prepublishOnly runs this automatically before npm publish, so the published tarball always contains a fresh build. Only dist/ is published (files: ["dist"]).

Project structure

src/              Component source (core + components, framework-agnostic)
dist/             Published bundles: doticca-ui.esm.js / .min.js / .css
example.html      Standalone HTML example that loads the built dist bundle
public/docs/      Static documentation site, served as the landing page
lib/mcp/          MCP registry (source of truth) + search/serve helpers
app/mcp/          MCP JSON API route handlers (AI-facing docs layer)
app/              Next.js app shell (hosts the docs)

Built with v0

This repository is linked to a v0 project. You can continue developing by visiting the link below — start new chats to make changes, and v0 will push commits directly to this repo. Every merge to main will automatically deploy.

Continue working on v0 →