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

@stnd/ui

v0.26.0

Published

--- title: "@stnd/ui" aliases: [] created: 2026-07-05 07:47 modified: 2026-09-16T18:33:35.950Z last_audited: 2026-07-14 audit_interval_days: 90 next_audit: 2026-10-12 audit_priority: 3 maturity: sprout mode: read publish: true status: active tags: - pac

Readme


title: "@stnd/ui" aliases: [] created: 2026-07-05 07:47 modified: 2026-09-16T18:33:35.950Z last_audited: 2026-07-14 audit_interval_days: 90 next_audit: 2026-10-12 audit_priority: 3 maturity: sprout mode: read publish: true status: active tags:

  • package
  • stnd theme: maker type: package visibility: public garden-url: https://standard.garden/@francis/readme garden-short: https://stnd.gd/Yl18ps permalink: readme

@stnd/ui

Shared UI components for the Standard Ecosystem.


Most buttons/badges/cards should just be a CSS class on plain HTML (see @stnd/styles) — no JS, no import. This package is only for the handful of things that genuinely need interactivity: a dropdown that manages keyboard navigation, a confirm dialog you can await, a right-click menu. If you’re reaching for a component here and it’s not doing something stateful or ARIA-heavy, check whether a CSS class already does the job.

Use it (the confirm dialog, the most common one):

import { confirm } from "@stnd/ui/dialog.js";
const ok = await confirm({ title: "Delete this?", intent: "danger" });

Overview

@stnd/ui provides a collection of reusable, accessible, and high-quality UI components built for Astro and Svelte 5. These components are designed to work seamlessly with @stnd/styles and follow the Standard design principles.

The Philosophy: CSS First, Components Second

Standard is built on the philosophy of keeping the codebase as clean, fast, and static as possible. Before importing a component from @stnd/ui, ask yourself: Can this be done with just HTML and @stnd/styles?

Many UI elements you see in the Playground (like Buttons, Badges, Cards, and Inputs) are not components. They are simple CSS classes applied to standard HTML elements.

Why?

  • Zero JavaScript overhead.
  • Perfect semantic HTML.
  • Maximum flexibility without passing dozens of props.

Example: Buttons & Badges (CSS Only)

You do not need a <Button> or <Badge> component. Just use the global classes provided by @stnd/styles:

<!-- Primary Button -->
<button class="btn">Save Changes</button>

<!-- Ghost Button -->
<button class="btn ghost">Cancel</button>

<!-- Success Badge -->
<span class="badge success">Active</span>

When to use @stnd/ui Components?

You should only import components from this package when you need:

  1. Complex interactivity (e.g., Dropdown, ContextMenu).
  2. State management (e.g., DialogManager, ComboBox).
  3. Advanced Accessibility / ARIA management (e.g., Accordion).
  4. Complex composition (e.g., Accordion, Scroller, TableOfContents).

Icons and Lottie animations are not in this package — they live in @stnd/icon (import Icon from "@stnd/icon/Icon.astro"). See its README.


Component API Reference

Astro Components (Zero JS)

<Header />

Minimalist responsive application and website header with brand wordmark, desktop menu, mobile navigation, and action slots.

  • brand (string): Brand text or logo label (defaults to site config title).
  • brandHref (string): Link target for the brand.
  • items (Array): Navigation items ({ title, url, external }).
  • menu (boolean): Whether to render navigation menu and burger toggle.
  • startHidden (boolean): When true, starts hidden and appears on scroll-up.

<Footer />

Flexible website footer with brand column, navigation links, copyright, and slots (brand, description, copyright, studio, bottom-left, bottom-right).

  • title (string): Brand or site name.
  • hideBrand (boolean): Hides the brand column.
  • hideNav (boolean): Hides the navigation links column.

<Accordion />

Accessible, collapsible content sections.

  • open (boolean): Sets the initial open state.

<Breadcrumb />

The trail to the current page. The last item is the current page: not a link, aria-current="page".

  • items ({ label, href? }[]): The trail, from the root down.
  • label (string): What the trail is called for screen readers (default Breadcrumb).

<Empty />

What a list or a page says when there is nothing to show yet.

  • title (string): The headline.
  • icon (string): Optional icon above it.
  • Slots: the default slot is the explanation; action holds the way out (a button or a link).

<Stat />

One figure and what it measures.

  • label, value (string | number): The name and the figure.
  • hint (string), change (string): A note under the figure, and the change since last time.
  • tone (success | warning | error): Colours the figure when it says something about health.

No component needed: a progress bar is the native <progress>, and a loading placeholder is the .skeleton class (both live in @stnd/styles, see the forms and components pages).


Svelte 5 Components (Hydrated)

<Alert />

Semantic feedback banners.

  • class (string): The semantic intent: success, warning, error, info. (Defaults to accent color).
  • title (string): Optional bold title.
  • icon (string): Optional string icon (e.g., ✓, ⚠).
<Alert class="warning" title="Watch out!" icon="⚠">
  This action cannot be undone.
</Alert>

<Tabs />

A row of tabs and the panel of the selected one. Arrow keys, Home and End move between tabs; only the selected panel is rendered.

  • tabs ({ id, label, icon?, disabled? }[]): The tabs.
  • value (string, bindable): The id of the selected tab (defaults to the first enabled one).
  • label (string): What the row is for, said to screen readers.
  • Snippets: panel(tab) renders the content of the selected tab; end sits at the far end of the row.
<Tabs {tabs} bind:value label="Period">
  {#snippet panel(tab)}...{/snippet}
</Tabs>

<OtpInput />

The boxes of a one-time code: focus moves on as you type, back on Backspace, a pasted code fills them all.

  • length (number, default 6), numeric (boolean, default true), label, disabled.
  • value (string, bindable): The code so far.
  • oncomplete(code): Called once the last box is filled.

<Tree />

A nested list that opens and closes by branch, on native <details>.

  • nodes ({ id, label, href?, icon?, children? }[]): The tree.
  • current (string): The id of the current node; its branches are open.
  • onselect(node): Called when a node is chosen.

<Dropdown />

Accessible, keyboard-navigable dropdown menus.

  • align (string): Alignment of the menu (start, end). Defaults to start.
  • label (string): Recommended accessible name for the native trigger button. When supplied, the trigger snippet contains only its content (not another button).
  • triggerClass (string): CSS classes applied to the generated native trigger button.
  • open (boolean, bindable): Controls or tracks the menu's open state.
  • Slots / Snippets: trigger (the button content or trigger element), default (the menu items).
  • Keyboard & Dismissal:
    • ArrowUp / ArrowDown and Home / End move focus among enabled items.
    • Escape dismisses the menu and restores focus to the trigger.
    • Tab dismisses the menu and continues normal focus navigation.
    • Item activation closes the menu automatically without double-toggling native button triggers.

Related Sub-components:

  • <DropdownItem icon="ph:user" shortcut="⌘P">Profile</DropdownItem>
  • <DropdownLabel label="My Account" />
  • <DropdownSeparator />

<ContextMenu />

Viewport-aware right-click menus.

  • Slots / Snippets: default (the area that triggers the menu on right-click), content (the menu items).
  • Controlled / Delegated Mode: For virtualized or delegated targets, omit the default snippet and pass open (bindable), position={{ x, y }} (viewport coordinates), label, and onclose.
  • Viewport Clamping: Measures actual menu dimensions, clamps coordinates to stay within the viewport, and scrolls oversized menus automatically.
  • Keyboard & Dismissal:
    • ArrowUp / ArrowDown and Home / End move focus among enabled items.
    • Escape, Tab, outside clicks, viewport resize, and outside scroll dismiss the menu and restore focus when appropriate.
    • Context-menu item components synchronize both native disabled attributes and aria-disabled.

<DataTable />

A table whose column headers sort on click. Click a header (or press Enter/Space on it) to cycle ascending → descending → original order. Output is a plain <table> styled by @stnd/styles; the sort state is exposed through aria-sort and announced politely to screen readers.

<DataTable
  {rows}
  rowKey="id"
  locale="fr"
  columns={[
    { key: "name", header: "Station" },
    { key: "bikes", header: "Bikes", numeric: true },
    { key: "trend", header: "Trend", sortable: false },
  ]}
>
  {#snippet cell({ row, column, value })}
    {#if column.key === "trend"}<Sparkline data={row.trend} />{:else}{value}{/if}
  {/snippet}
</DataTable>
  • rows (array) and columns ({ key, header, sortable = true, numeric = false, accessor?, class? }[]). accessor(row) sorts and renders computed values.
  • rowKey (string or (row) => key): stable row identity, so selection and DOM state survive a re-sort. Falls back to the index.
  • sort (bindable { key, direction }, direction ascending | descending | none): start sorted or persist the choice.
  • locale: collation for text ("fr" ignores accents and sorts "10" after "9"). Empty values (null, undefined, "") always sort last.
  • selectedKey + onrowclick(row): makes rows focusable and clickable (Enter/Space), highlights the selected one. Links and buttons inside a row keep their own behaviour.
  • labels ({ ascending, descending, none }) translate the screen-reader announcement; caption, class (defaults to striped).
  • Snippets: cell({ row, column, value }) for custom cells, header({ column }) for custom header content, empty() for the full-width row shown when there are no rows.
  • manualSort: you order rows yourself (paginated or server-side lists, where sorting only the visible page would be wrong). Bind sort and apply it with sortRows from sort.js before slicing the page.

The comparison logic lives in sort.js (sortRows, compare, nextDirection) and works on any array without the component.

<Dialog />

A general-purpose native modal shell for forms and arbitrary content. This complements AlertDialog and confirm() without imposing confirmation semantics.

<Dialog bind:open label="Preferences" onclose={discardDraft}
  style="--dialog-width: 580px; --dialog-max-height: 88vh">
  <!-- Form content and semantic buttons belong to the consumer. -->
</Dialog>
  • Props:
    • open (boolean, bindable): Controls modal visibility via native showModal().
    • label (string, required): Accessible dialog name (aria-label).
    • children (Snippet): Modal body content.
    • class / style (string): Customizes the <dialog> shell (e.g. --dialog-width, --dialog-max-height).
    • onclose / onkeydown (function): Lifecycle and content-specific keyboard callbacks.
  • Behavior & Accessibility:
    • Manages native showModal(), background inertness, focus trapping, Escape / backdrop dismissal, and focus restoration.
    • Stops keyboard event propagation from reaching global application shortcut listeners.
    • Intended for modal interactions (not non-modal floating monitors or OS windows).

<Popover />

An anchored, non-modal popup for forms and mixed controls. Use Dropdown for action menus instead.

<Popover label="Display options" align="end">
  {#snippet trigger(attributes)}
    <button class="btn ghost" {...attributes}>Display</button>
  {/snippet}
  <!-- Native inputs and content-specific buttons. -->
</Popover>
  • Props:
    • label (string, required): Accessible name for the popover region.
    • open (boolean, bindable): Controls or tracks open state.
    • trigger(attributes) (Snippet): Spread attributes onto a single native <button> to wire click handling and ARIA relationships.
    • children (Snippet): Popover body content.
    • align ("start" | "end") and side ("bottom" | "top"): Anchor placement relative to the trigger.
    • class (string) and onclose (function): Optional wrapper class and close callback.
  • Keyboard & Dismissal:
    • Escape dismisses the popover and restores focus to the trigger.
    • Clicking outside or moving focus out of both the popup and trigger dismisses the popover.
    • Keyboard events inside the popover do not leak to global application shortcuts.
  • Validation & Testing:
    • Shared menu geometry and navigation helpers are tested via node --test packages/ui/menu.test.js.
    • See Reveal UI validation for browser regression coverage across context menus, dropdowns, popovers, and dialogs.

Dialog Manager

The DialogManager allows you to trigger accessible confirmation dialogs programmatically from any script using a simple Promise-based API. This prevents littering your DOM with hidden modal HTML.

AlertDialog can also be composed directly inside an existing Dialog when confirmation belongs to that form. Its title provides the accessible dialog name, keyboard events stay within the confirmation instead of reaching parent form shortcuts, and a programmatic close after confirmation does not also call the cancellation callback.

1. Mount the Manager

Ensure <DialogManagerComponent client:load /> is mounted once in your root layout (Standard does this by default).

2. Call the API

import { confirm } from "@stnd/ui/dialog.js";

const isConfirmed = await confirm({
  title: "Delete this item?",
  description: "This action cannot be undone. Are you sure?",
  confirmLabel: "Yes, Delete",
  cancelLabel: "Cancel",
  intent: "danger" // "neutral" | "danger"
});

if (isConfirmed) {
  // Proceed with deletion
}

Notes / Observations

(jot down anything noticed here — quirks, gotchas, ideas)

Todo

  • [ ] README still lacks Combobox, Pagination, Scroller, TableOfContents, Toast, CfImage, LauncherHint and ColorModeToggle. Each has an @component block in its source; copy it here. [priority:: 3] [token_scale:: 3] [created:: 2026-07-14] [area:: framework]