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

@yetric/ui

v0.6.0

Published

Shared React UI foundation for Yetric applications.

Readme

@yetric/ui

A practical React component library built for modern applications — including AI-native UIs.

@yetric/ui gives you a complete set of accessible, composable components that cover everyday UI needs, advanced data patterns, and the streaming/chat interfaces that AI-powered apps demand. Provider-agnostic by design: bring your own backend, your own geocoding, your own LLM.

Install

npm install @yetric/ui

What's included

Core components

Button, Input, Textarea, Select, Checkbox, RadioGroup, Switch, Slider, Label, Badge, Avatar, Card, Alert, Dialog, AlertDialog, Popover, Tooltip, DropdownMenu, ContextMenu, Sheet, Drawer, Tabs, Accordion, Collapsible, HoverCard, Menubar, NavigationMenu, Command, Pagination, Breadcrumb, Stepper, Timeline, Table, DataTable, Skeleton, Spinner, Progress, Separator, ScrollArea, ResizablePanel, Carousel, Calendar, InputOTP, TagsInput, MultiSelect, PinInput, Code, Toggle, ToggleGroup, Toolbar

Advanced components (0.5.0+)

DatePicker, DateRangePicker, FileUpload, Image, ColorPicker, Charts (Line/Bar/Area/Pie), EmptyState, ConfirmDialog, Toast API

Power components (0.6.0+)

DataGrid (virtualized), RichTextEditor (Tiptap), MapView (Leaflet/OpenStreetMap), CommandPalette (⌘K), PhoneInput, AddressInput (provider-agnostic), Tour, VideoPlayer, LoginForm, SignupForm

AI components (coming in 0.7.0)

AIChat, StreamingText, PromptInput, AIMessage, ThinkingIndicator, ModelSelector, SuggestionChips

Quick start

import { Button, Card, CardContent, CardHeader, CardTitle } from "@yetric/ui";
import "@yetric/ui/dist/index.css";

export function Example() {
  return (
    <Card>
      <CardHeader>
        <CardTitle>Welcome</CardTitle>
      </CardHeader>
      <CardContent>
        <Button>Get started</Button>
      </CardContent>
    </Card>
  );
}

AI-native usage (0.7.0)

import { AIChat } from "@yetric/ui";

export function Assistant() {
  return (
    <AIChat
      onSend={async (message) => {
        const res = await fetch("/api/chat", {
          method: "POST",
          body: JSON.stringify({ message }),
        });
        return res.body; // ReadableStream
      }}
    />
  );
}

Provider-agnostic patterns

Components like AddressInput, DataGrid, and the upcoming AI components take callbacks instead of hardcoded integrations:

// Bring your own geocoding
<AddressInput
  onSearch={async (query) => {
    const res = await fetch(`/api/geocode?q=${query}`);
    return res.json(); // AddressSuggestion[]
  }}
/>

// Bring your own LLM
<AIChat onSend={(msg) => streamFromAnyProvider(msg)} />

Tech stack

The intended foundation is:

React
TypeScript
Radix UI primitives
Tailwind CSS
class-variance-authority
tailwind-merge
Storybook
Vitest
React Testing Library
tsup or Vite library mode

Design approach

The library should use proven accessible primitives for behavior-heavy components and focus our own work on visual design, API consistency, composition, and documentation.

Build ourselves:

component APIs
styling conventions
variants
design tokens
layout primitives
documentation
business-friendly usage examples

Avoid rebuilding from scratch:

focus trapping
keyboard navigation
ARIA behavior
popover positioning
menu behavior
dialog behavior
combobox behavior
screen reader edge cases

Component principles

  • Keep core components domain-free.
  • Prefer composition over large configuration objects.
  • Use accessible primitives for complex behavior.
  • Keep APIs boring and predictable.
  • Use TypeScript types as part of the component contract.
  • Use Storybook to document real usage.
  • Add at least basic tests for every reusable component.
  • Do not put app-specific business logic in @yetric/ui.
  • Business components should live in a separate package or app layer.

Suggested package structure

packages/
  ui/
    src/
      components/
        button/
          Button.tsx
          Button.test.tsx
          Button.stories.tsx
          index.ts
        card/
          Card.tsx
          Card.stories.tsx
          index.ts
        dialog/
          Dialog.tsx
          Dialog.stories.tsx
          index.ts
      lib/
        cn.ts
      styles/
        globals.css
      index.ts
    package.json
    tsconfig.json
    tailwind.config.ts
    tsup.config.ts

If this repository starts as a single-package repo instead of a monorepo, the same structure can live directly under src/.

Initial components

The first version should validate the foundation with a small set of components:

Button
Card
Dialog

These are enough to prove:

  • styling conventions
  • variants
  • composition
  • Radix wrapping
  • exports
  • Storybook setup
  • testing setup
  • package build

Example usage

import { Button, Card, CardContent, CardHeader, CardTitle } from "@yetric/ui";

export function Example() {
  return (
    <Card>
      <CardHeader>
        <CardTitle>Welcome</CardTitle>
      </CardHeader>
      <CardContent>
        <Button>Get started</Button>
      </CardContent>
    </Card>
  );
}

Styling utility

The library should include a small cn helper for combining conditional classes and resolving Tailwind conflicts.

import { clsx, type ClassValue } from "clsx";
import { twMerge } from "tailwind-merge";

export function cn(...inputs: ClassValue[]) {
  return twMerge(clsx(inputs));
}

Component variants

Use class-variance-authority for variant-heavy components.

Example:

<Button variant="primary" size="md">
  Save
</Button>

<Button variant="secondary" size="sm">
  Cancel
</Button>

<Button variant="danger">
  Delete
</Button>

Scripts

Suggested scripts:

{
  "scripts": {
    "build": "tsup src/index.ts --format esm --dts",
    "dev": "tsup src/index.ts --format esm --dts --watch",
    "storybook": "storybook dev -p 6006",
    "build-storybook": "storybook build",
    "test": "vitest",
    "test:run": "vitest run",
    "typecheck": "tsc --noEmit"
  }
}

Adjust scripts to match the final repository setup.

Development

Install dependencies:

npm install

Run Storybook:

npm run storybook

Run tests:

npm run test

Build the library:

npm run build

Run type checking:

npm run typecheck

Public exports

All public components should be exported from src/index.ts.

Example:

export * from "./components/button";
export * from "./components/card";
export * from "./components/dialog";
export * from "./lib/cn";

Consumers should not import from deep internal paths unless explicitly supported.

Preferred:

import { Button } from "@yetric/ui";

Avoid:

import { Button } from "@yetric/ui/src/components/button/Button";

Adding a new component

When adding a component:

  1. Create a folder under src/components/<component-name>/.
  2. Add the component implementation.
  3. Add an index.ts file for local exports.
  4. Add Storybook stories.
  5. Add basic tests.
  6. Export the component from src/index.ts.
  7. Document variants and important usage notes.

Recommended structure:

src/components/input/
  Input.tsx
  Input.test.tsx
  Input.stories.tsx
  index.ts

What belongs here

Good candidates for @yetric/ui:

Button
Input
Textarea
Checkbox
RadioGroup
Select
Dialog
DropdownMenu
Tabs
Tooltip
Popover
Card
Badge
Alert
Table primitives
Typography helpers
Layout primitives

What does not belong here

Avoid adding business-specific components to this package.

Examples that should probably live elsewhere:

AccountSelector
PaymentReceiverSelector
PayAmountField
BookingCalendar
RestaurantTableMap
PropertyValuationForm
LeadCaptureFlow

Those components can still use @yetric/ui, but they should live in app-specific packages or a separate business UI package.

Possible future package:

@yetric/ui-business

Accessibility

Accessibility is a core reason for using primitives like Radix UI.

Components should support:

  • keyboard navigation
  • focus states
  • disabled states
  • accessible names and labels
  • screen reader-friendly structure
  • sensible default semantics

Do not remove accessibility behavior from underlying primitives unless there is a very good reason.

Testing expectations

Each reusable component should have at least basic tests.

Minimum expectations:

  • renders without crashing
  • renders children/content
  • supports important variants
  • supports disabled state where relevant
  • supports basic interaction where relevant

For behavior-heavy components, test the behavior that matters to consumers.

Example:

Dialog opens when trigger is clicked.
Dialog content is visible when open.
Button is disabled when disabled=true.

Storybook expectations

Each component should have stories for:

  • default state
  • variants
  • sizes, if applicable
  • disabled/loading/error states, if applicable
  • realistic usage example

Storybook should be treated as the main component documentation.

Versioning

Use semantic versioning once the package is consumed by real applications.

patch: bug fixes and internal improvements
minor: new components or backwards-compatible additions
major: breaking API or styling contract changes

Future direction

Possible future additions:

@yetric/ui-icons
@yetric/ui-theme
@yetric/ui-forms
@yetric/ui-business
internal component registry
visual regression testing
theme switching
React Hook Form adapters
application shell components

Do not add these until there is a real need.

Guiding idea

Start small. Keep it useful. Avoid building a museum of abstractions.

The best version of this library is boring, predictable, accessible, and easy to use.