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

@monowind/ui-react

v0.3.5

Published

@monowind/ui as React hooks: a menu, a listbox, a select, a combobox, a dialog, a popover, a tooltip, a collapsible, an accordion on the monowind grid

Readme

@monowind/ui-react

@monowind/ui for React, two ways over the same machines: a component per piece — Menu, Listbox, Select, Combobox, Dialog, Popover, Tooltip, Collapsible, Accordion — and a hook per component — useMenu, useListbox, useSelect, useCombobox, useDialog, usePopover, useTooltip, useCollapsible, useAccordion. Style the parts with Tailwind and monowind classes; the engine places each floating part against its trigger in cells, in the top layer.

import { Menu } from "@monowind/ui-react";

const ITEM = "px-1 data-highlighted:bg-(--mw-fg) data-highlighted:text-(--mw-bg)";

function FileMenu() {
  return (
    <Menu.Root positioning={{ placement: "bottom-start" }}>
      <Menu.Trigger className="border px-1">File</Menu.Trigger>
      <Menu.Positioner>
        <Menu.Content className="border bg-clear">
          <Menu.Item value="new" className={ITEM}>
            New
          </Menu.Item>
          <Menu.Root>
            <Menu.TriggerItem className={ITEM}>Share ›</Menu.TriggerItem>
            <Menu.Positioner>
              <Menu.Content className="border bg-clear">
                <Menu.Item value="mail" className={ITEM}>
                  Mail
                </Menu.Item>
              </Menu.Content>
            </Menu.Positioner>
          </Menu.Root>
        </Menu.Content>
      </Menu.Positioner>
    </Menu.Root>
  );
}

The components

Root takes the machine's props — id optional, a useId() standing in — and holds the API for the parts under it. The parts:

  • Menu — Trigger, TriggerItem, Positioner, Content, Item, ItemGroup, ItemGroupLabel, Separator.
  • Dialog and Popover — Trigger, Positioner, Content, Title, Description, CloseTrigger; the popover also has Indicator.
  • Tooltip — Trigger, Positioner, Content, which render inline, a tooltip belonging in the sentence around its trigger.
  • Listbox and Select — Root, which is an element of its own (Zag gives both a root part, so it takes attributes as any part does), Label, Content, Item, ItemText, ItemIndicator, ItemGroup, ItemGroupLabel; the select adds Control, Trigger, ValueText, Indicator, ClearTrigger, Positioner, List and HiddenSelect, the native control a form submits — its options in the server's render too, so a form sent before hydration posts the initial value.
  • Combobox — Root (an element of its own), Label, Control, Input, Trigger, ClearTrigger, Positioner, Content, List, and the item parts above. Its list anchors to the Control, so it lines up under the input; filtering is yours — give Root the collection your input value narrows, and the items it leaves out are hidden.
  • Collapsible — Root (an element of its own), Trigger, Content, Indicator.
  • Accordion — Root (an element of its own), Item, ItemTrigger, ItemContent, ItemIndicator; an Item holds its value and disabled for the parts inside, which Accordion.useAccordionItemContext() reads.

A menu's, a dialog's, a popover's and a tooltip's Root render nothing — Zag gives those four no root part, and a wrapper invented for one would put a box in the grid's layout — so they take no attributes, and a className on one is a type error and, in a development build, a warning naming it. A listbox's, a select's, a combobox's, a collapsible's and an accordion's root renders its part and takes attributes as any part does.

An Item names one of the collection's items, by item or by the value that finds it there, and holds it for the ItemText and ItemIndicator inside; Listbox.useListboxItemContext(), Select.useSelectItemContext() and Combobox.useComboboxItemContext() read it. The item parts read the nearest listbox, select or combobox root, whichever of the three they are named for. Select.ValueText shows what is selected, its children the placeholder until something is. A Menu.Root inside another is that menu's submenu: Zag links the two, and the submenu takes the side it opens on (right-start, or left-start in a right-to-left menu) and the behavior its parent shares — onSelect, closeOnSelect, loopFocus, typeahead, composite, navigate, dir, getRootNode — with its own props over them, exactly as a marked submenu root does. Its Menu.TriggerItem is the parent's item that opens it, so it goes inside the nested Root.

A part takes the props of the element it renders, so Menu.Trigger autocompletes a button's and a typo is an error, and a ref reaches the node.

Every part merges the API's props under yours with Zag's own mergeProps: your class comes after the API's, and a handler of yours runs before the API's. asChild renders the one child instead of the part's own element, with those props merged onto it — refs from both sides reach the node:

<Menu.Trigger asChild>
  <MyButton className="border px-1">File</MyButton>
</Menu.Trigger>

RootProvider takes an API you hold, for reaching it from outside the tree: run the hook yourself and hand it over.

function FileMenu() {
  const menu = useMenu({ id: "file" });
  return <Menu.RootProvider value={menu}>{/* the parts */}</Menu.RootProvider>;
}

A context hook per component — Menu.useMenuContext(), Accordion.useAccordionContext() and the rest — gives a part the component it is in, exactly as its hook returns it.

The hooks

Each takes Zag's machine props (id required) and returns Zag's API with the grid's props on the trigger, the positioner, and the content, the positioner's ref inside getPositionerProps() so its place in the top layer follows the machine, and the machine's service beside the API for linking two machines. A listbox, a collapsible and an accordion stand in the flow, so useListbox, useCollapsible and useAccordion return no positioner. Spread the props as Zag's docs show.

import { useMenu } from "@monowind/ui-react";
import { useId } from "react";

function FileMenu() {
  const menu = useMenu({ id: useId(), positioning: { placement: "bottom-start" } });
  return (
    <>
      <button {...menu.getTriggerProps()} className="border px-1">
        File
      </button>
      <div {...menu.getPositionerProps()}>
        <div {...menu.getContentProps()} className="border bg-clear">
          <div
            {...menu.getItemProps({ value: "new" })}
            className="px-1 data-highlighted:bg-(--mw-fg) data-highlighted:text-(--mw-bg)"
          >
            New
          </div>
        </div>
      </div>
    </>
  );
}

The parts, their states, and positioning (placement, gutter, offset, in cells) are @monowind/ui's — see its README.