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/solid

v0.1.0

Published

AI-native unstyled primitives for your design system. Headless, compound components with zero CSS — style via data-* attributes. SolidJS edition.

Downloads

58

Readme


What is Wire UI?

Wire UI is an AI-native, headless component library. Every component ships with zero CSS — style everything using your own classes by targeting data-* attributes that reflect interactive state. AI-integrated docs with llms.txt and machine-readable API references make it built for AI-assisted workflows.

  • AI-native. AI-integrated docs with llms.txt, machine-readable API references, and MCP server support. Built for AI-assisted development.
  • Unstyled primitives. No colors, spacing, or fonts baked in. You own every pixel of your design.
  • Compound components. Complex widgets follow the Component.Part pattern, giving you full control over markup structure and element nesting.
  • State via data-* attributes. Hover, focus, pressed, disabled, open — all exposed as data-hover, data-focus-visible, data-active, etc.
  • 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.

Solid edition. This is the SolidJS port of @wire-ui/react, targeting Solid 1.9. Behaviour and data-attribute APIs match the React package exactly. See the Solid-specific notes below for the small idiomatic differences.

Documentation

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


Installation

npm install @wire-ui/solid

Peer requirement

{
  "solid-js": ">=1.9.0"
}

Quick start

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

export default function App() {
  return (
    <Button
      class="
        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 | | 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 class="[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:

import { createSignal } from 'solid-js'
import { Input } from '@wire-ui/solid'

function EmailField() {
  const [email, setEmail] = createSignal('')
  const [error, setError] = createSignal('')

  return (
    <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. The component evaluates the child to a DOM node and applies its data-* attributes and event listeners imperatively, so the child element renders as-is:

// 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>

Primitives

createInteractiveState

The same primitive used internally by Button, Accordion.Trigger, Modal.Close, and the rest — exported for building your own interactive elements. Pass an options object with a disabled getter to keep the value reactive:

import { createInteractiveState } from '@wire-ui/solid'

function MyCard(props: { disabled?: boolean }) {
  const state = createInteractiveState({
    get disabled() { return !!props.disabled },
  })

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

createClickOutside

Fires a callback when the user clicks outside a referenced element. Pass a getter accessor so the listener picks up ref changes:

import { createSignal } from 'solid-js'
import { createClickOutside } from '@wire-ui/solid'

function Popover() {
  const [, setOpen] = createSignal(true)
  let rootEl: HTMLDivElement | undefined

  createClickOutside(() => rootEl, () => setOpen(false))

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

Solid-specific notes

@wire-ui/solid mirrors the React package's behaviour and data-attribute API exactly. The differences are idiomatic to Solid:

  • class, not className. Solid uses the native HTML class attribute throughout.
  • createSignal over useState. Same controlled/uncontrolled pattern, just with accessors.
  • Primitives instead of hooks. useInteractiveStatecreateInteractiveState, useClickOutsidecreateClickOutside.
  • No forwardRef. Refs are passed as plain props or callbacks in Solid 1.x.
  • Show / For instead of conditional / array rendering. Necessary because Solid components run once at setup time.
  • Portal from solid-js/web. Used internally by Modal and Drawer in place of react-dom's createPortal.
  • Reactive options. Where React passes plain values (e.g. useInteractiveState({ disabled })), the Solid equivalent expects either a static value or an object with a get disabled() getter so reactivity is preserved.

Targets Solid 1.9 — Solid 2.0 is in beta as of March 2026; this package will track the 1.x line until 2.0 stabilises and a 2.x release lands.


TypeScript

All component props and utility types are exported:

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

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

Community

Authors


Contributing

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

License

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