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

@wire-ui/react

v0.1.6

Published

<p align="center"> <img src="https://raw.githubusercontent.com/wire-ui/wire-ui/main/apps/docs/public/images/logo/wire-ui-logo.svg" alt="Wire UI" height="52" /> </p>

Readme


What is Wire UI?

Wire UI is a headless component library for React 19. Every component ships with zero CSS — style everything using your own classes by targeting data-* attributes that reflect interactive state.

  • Unstyled by default. No colors, spacing, or fonts baked in. You own every pixel of your design.
  • State via data-* attributes. Hover, focus, pressed, disabled, open — all exposed as data-hover, data-focus-visible, data-active, etc. Style them with [data-hover]:bg-gray-100 in Tailwind or [data-hover] { ... } in plain CSS.
  • Compound components. Complex widgets follow the Component.Part pattern, giving you full control over markup structure and element nesting.
  • Controlled & uncontrolled. Every stateful component works both ways.
  • asChild polymorphism. Merge all behaviour onto your own element — perfect for router links, icon buttons, and custom wrappers.
  • Consumer-owned validation. Form components expose invalidType and errorMessage but never validate internally. Your logic, your rules.

Documentation

Full documentation with live examples is at wire-ui.com.


Installation

npm install @wire-ui/react

Peer requirements

{
  "react": ">=19.0.0",
  "react-dom": ">=19.0.0"
}

Quick start

import { Button } from '@wire-ui/react'

export default function App() {
  return (
    <Button
      className="
        px-4 py-2 rounded-lg bg-indigo-600 text-white font-medium
        [data-hover]:bg-indigo-700
        [data-active]:scale-95
        [data-focus-visible]:ring-2 [data-focus-visible]:ring-indigo-500
        [data-disabled]:opacity-40 [data-disabled]:cursor-not-allowed
      "
    >
      Save changes
    </Button>
  )
}

Components

Form inputs

| Component | Description | |---|---| | Input | Text input with label, error, and success states | | Textarea | Multi-line input with the same compound API as Input | | Password | Input with a built-in show/hide toggle | | Checkbox | Group and individual checkbox items | | Radio | Single-selection radio group | | Switch | Toggle on/off with a thumb element | | OTP | One-time password input with individual slots | | Select | Accessible select menu with groups and separators | | Search | Search input with keyboard-navigable results list |

Overlay & dialog

| Component | Description | |---|---| | Modal | Dialog with portal rendering, overlay click-to-close, and Escape key | | Drawer | Side-panel dialog — same structure as Modal | | Dropdown | Trigger + floating menu with click-outside support | | Tooltip | Hover/focus tooltip with configurable delay and side |

Layout & navigation

| Component | Description | |---|---| | Accordion | Collapsible sections — single or multiple open mode | | Divider | Horizontal or vertical separator |

Display

| Component | Description | |---|---| | Alert | Dismissible alert with optional auto-dismiss | | Avatar | Image with a text/initial fallback | | Badge | Numeric count badge, capped at 9+ | | Card | Container with optional color and size variants | | Icon | SVG renderer from a consumer-supplied icon map | | Image | Image with a loading placeholder | | List | Ordered/unordered list with optional dividers and striping | | ProgressBar | Accessible progress indicator | | Rating | Interactive or read-only star rating | | Spinner | Animated 12-dot loading indicator | | Timeago | Relative or formatted timestamp that updates live |


Key concepts

Data attributes

Attributes are present as an empty string when active, and absent when not — never "true" or "false".

| Attribute | When present | |---|---| | data-hover | Mouse is over the element | | data-focus-visible | Keyboard focus (mirrors :focus-visible) | | data-active | Element is being pressed | | data-disabled | Element is disabled | | data-state | Open/closed, checked/unchecked — varies per component | | data-invalid | Consumer-controlled via invalidType | | data-success | Consumer-controlled via isSuccess |

Style them in Tailwind:

<Button className="[data-hover]:bg-blue-700 [data-active]:scale-95 [data-disabled]:opacity-50">

Or in plain CSS:

button[data-hover]  { background: #1d4ed8; }
button[data-active] { transform: scale(0.95); }

Compound components

Complex widgets follow the Component.Part pattern so you control the structure:

<Input.Root value={email} onChange={setEmail} invalidType={error}>
  <Input.Label>Email</Input.Label>
  <Input.Field type="email" placeholder="[email protected]" />
  <Input.Error />
</Input.Root>

asChild polymorphism

Pass asChild to merge behaviour onto your own element:

// Renders as <a> but with all Button data attributes
<Button asChild>
  <a href="/dashboard">Go to dashboard</a>
</Button>

Consumer-owned validation

Set invalidType to a key and the component renders the matching error message — no internal validation ever runs:

<Input.Root
  invalidType={error}         // e.g. "required" or "email"
  errorMessage={{
    required: 'Email is required',
    email: 'Enter a valid email address',
  }}
>
  <Input.Field type="email" />
  <Input.Error />   {/* renders the matching message */}
</Input.Root>

Hooks

useInteractiveState

The same hook used internally by Button, Accordion.Trigger, and Modal.Close — exported for building your own interactive elements.

import { useInteractiveState } from '@wire-ui/react'

function MyCard({ disabled }: { disabled?: boolean }) {
  const { handlers, dataAttributes } = useInteractiveState({ disabled })

  return (
    <div
      {...handlers}
      {...dataAttributes}
      className="[data-hover]:bg-gray-100 [data-active]:scale-95"
    >
      Card content
    </div>
  )
}

useClickOutside

Fires a callback when the user clicks outside a referenced element.

import { useRef } from 'react'
import { useClickOutside } from '@wire-ui/react'

function Popover() {
  const ref = useRef<HTMLDivElement>(null)
  useClickOutside(ref, () => setOpen(false))

  return <div ref={ref}>Popover content</div>
}

TypeScript

All component props and utility types are exported:

import type {
  ButtonProps,
  InputRootProps,
  TextareaRootProps,
  PasswordRootProps,
  ModalRootProps,
  AccordionRootProps,
  SearchOption,
  IconSize,
  Size,
  Status,
  InteractiveStateOptions,
  InteractiveStateResult,
} from '@wire-ui/react'

Development

# Install dependencies (from monorepo root)
npm install

# Run Storybook
npm run storybook

# Unit tests (watch mode)
npm test

# Unit tests (single run)
npm run test:run

# Unit tests with coverage
npm run test:coverage

# Type check + build
npm run build

# Lint
npm run lint

# Format
npm run format

Authors


Contributing

See the contributing guide for local development instructions and pull request guidelines.

License

MIT License © 2025 Wire UI. See LICENSE for details.