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

@zentrades-ui/components

v0.3.2

Published

React component library for the Zen UI kit. Built with accessibility in mind using Radix UI primitives.

Readme

@zentrades-ui/components

React component library for the Zen UI kit. Built with accessibility in mind using Radix UI primitives.

Installation

pnpm add @zentrades-ui/components @zentrades-ui/theme @zentrades-ui/tokens

Styles

This package ships extracted CSS. Import the global styles once:

import "@zentrades-ui/components/dist/index.css";

Or import per-component CSS if you only consume a subset:

import "@zentrades-ui/components/dist/components/Button/index.css";
import "@zentrades-ui/components/dist/components/Input/index.css";

Quick Start

import { ThemeProvider } from "@zentrades-ui/theme";
import { Button, Input, Stack } from "@zentrades-ui/components";

export function Example() {
  return (
    <ThemeProvider theme="light">
      <Stack gap="md">
        <Input label="Email" placeholder="Enter your email" />
        <Button>Submit</Button>
      </Stack>
    </ThemeProvider>
  );
}

Components

Form Components

All form components share a consistent API:

| Prop | Type | Description | |------|------|-------------| | label | string | Label text displayed above/beside the input | | required | boolean | Shows required indicator (*) | | helperText | string | Helper text displayed below the input | | error | boolean | Error state styling | | errorMessage | string | Error message (replaces helperText when error is true) | | disabled | boolean | Disabled state |

Input

import { Input } from "@zentrades-ui/components";

<Input
  label="Email"
  placeholder="Enter your email"
  required
  helperText="We'll never share your email"
/>

<Input
  label="Password"
  type="password"
  error
  errorMessage="Password is required"
/>

// With icons
<Input
  label="Search"
  leftIcon={<SearchIcon />}
  icon={<ClearIcon />}
/>

// Horizontal layout
<Input label="Name" horizontal />

// Compound input with sections
<Input
  label="Price"
  leadingSection={<span>$</span>}
  trailingSection={<span>USD</span>}
/>

TextArea

import { TextArea } from "@zentrades-ui/components";

<TextArea
  label="Description"
  placeholder="Enter description..."
  required
  helperText="Max 500 characters"
/>

// View mode (read-only with different styling)
<TextArea label="Notes" viewMode value="Read-only content" />

// Hide resize handle
<TextArea label="Fixed" showResizeHandle={false} />

Checkbox

import { Checkbox } from "@zentrades-ui/components";

<Checkbox label="Accept terms" required />

<Checkbox
  label="Subscribe to newsletter"
  helperText="You can unsubscribe at any time"
/>

<Checkbox
  label="Agree to policy"
  error
  errorMessage="You must accept the policy"
/>

// Sizes: xs, sm, md, lg
<Checkbox label="Small" size="sm" />

// Indeterminate state
<Checkbox label="Select all" partialChecked />

Alignment behavior:

  • Without helperText: Checkbox and label are center-aligned
  • With helperText: Checkbox aligns with the label (top), helper text appears below the label

Switch

import { Switch } from "@zentrades-ui/components";

<Switch label="Enable notifications" />

<Switch
  label="Dark mode"
  helperText="Enable dark theme"
/>

<Switch
  label="Required setting"
  required
  error
  errorMessage="This must be enabled"
/>

// Sizes: sm, md, lg
<Switch size="lg" />

Select

import { Select } from "@zentrades-ui/components";

<Select
  label="Country"
  placeholder="Select a country"
  options={[
    { value: "us", label: "United States" },
    { value: "uk", label: "United Kingdom" },
    { value: "ca", label: "Canada" },
  ]}
/>

// Multi-select
<Select
  label="Tags"
  multiple
  options={tags}
/>

// Searchable
<Select
  label="Search users"
  searchable
  options={users}
/>

Layout Components

Stack

Vertical layout with consistent spacing:

import { Stack } from "@zentrades-ui/components";

<Stack gap="md">
  <div>Item 1</div>
  <div>Item 2</div>
  <div>Item 3</div>
</Stack>

// With alignment
<Stack gap="lg" alignItems="center">
  <Logo />
  <Title />
</Stack>

Inline

Horizontal layout with consistent spacing:

import { Inline } from "@zentrades-ui/components";

<Inline gap="sm" alignItems="center">
  <Avatar />
  <Text>Username</Text>
  <Badge>Admin</Badge>
</Inline>

// Wrap items
<Inline gap="xs" flexWrap="wrap">
  {tags.map(tag => <Chip key={tag}>{tag}</Chip>)}
</Inline>

Box

Base layout primitive with full styling props:

import { Box } from "@zentrades-ui/components";

<Box
  padding="md"
  backgroundColor="backgroundSecondary"
  borderRadius="md"
  borderWidth="xs"
  borderColor="borderTertiary"
>
  Content
</Box>

Feedback Components

Button

import { Button } from "@zentrades-ui/components";

// Variants
<Button variant="primary">Primary</Button>
<Button variant="secondary">Secondary</Button>
<Button variant="outline">Outline</Button>
<Button variant="ghost">Ghost</Button>
<Button variant="danger">Danger</Button>

// Sizes
<Button size="sm">Small</Button>
<Button size="md">Medium</Button>
<Button size="lg">Large</Button>

// With icons
<Button leftIcon={<PlusIcon />}>Add Item</Button>
<Button rightIcon={<ArrowIcon />}>Next</Button>

// Loading state
<Button loading>Submitting...</Button>

// Full width
<Button fullWidth>Submit</Button>

Toast

import { toast } from "@zentrades-ui/components";

toast.success("Changes saved!");
toast.error("Something went wrong");
toast.info("New update available");
toast.warning("Please review your input");

// Custom options
toast.success("Saved!", {
  duration: 5000,
  position: "top-right",
});

Dialog / AlertDialog

import { Dialog, AlertDialog } from "@zentrades-ui/components";

// Controlled dialog
<Dialog open={open} onOpenChange={setOpen}>
  <Dialog.Content title="Edit Profile">
    <form>...</form>
  </Dialog.Content>
</Dialog>

// Alert dialog (requires confirmation)
<AlertDialog
  open={open}
  onOpenChange={setOpen}
  title="Delete item?"
  description="This action cannot be undone."
  onConfirm={handleDelete}
/>

Data Display

Avatar

import { Avatar } from "@zentrades-ui/components";

<Avatar src="/avatar.jpg" alt="User" />
<Avatar name="John Doe" /> {/* Shows initials */}

// Sizes
<Avatar size="sm" name="JD" />
<Avatar size="lg" name="JD" />

Badge

import { Badge } from "@zentrades-ui/components";

<Badge>Default</Badge>
<Badge variant="success">Active</Badge>
<Badge variant="warning">Pending</Badge>
<Badge variant="error">Failed</Badge>
<Badge variant="info">New</Badge>

Chip

import { Chip } from "@zentrades-ui/components";

<Chip>Tag</Chip>
<Chip onRemove={() => {}}>Removable</Chip>
<Chip selected>Selected</Chip>

Navigation

Tabs

import { Tabs } from "@zentrades-ui/components";

<Tabs defaultValue="tab1">
  <Tabs.List>
    <Tabs.Trigger value="tab1">Overview</Tabs.Trigger>
    <Tabs.Trigger value="tab2">Settings</Tabs.Trigger>
  </Tabs.List>
  <Tabs.Content value="tab1">Overview content</Tabs.Content>
  <Tabs.Content value="tab2">Settings content</Tabs.Content>
</Tabs>

Breadcrumb

import { Breadcrumb } from "@zentrades-ui/components";

<Breadcrumb>
  <Breadcrumb.Item href="/">Home</Breadcrumb.Item>
  <Breadcrumb.Item href="/products">Products</Breadcrumb.Item>
  <Breadcrumb.Item>Current Page</Breadcrumb.Item>
</Breadcrumb>

Menu

import { Menu } from "@zentrades-ui/components";

<Menu>
  <Menu.Trigger asChild>
    <Button>Options</Button>
  </Menu.Trigger>
  <Menu.Content>
    <Menu.Item onClick={handleEdit}>Edit</Menu.Item>
    <Menu.Item onClick={handleDuplicate}>Duplicate</Menu.Item>
    <Menu.Separator />
    <Menu.Item onClick={handleDelete} destructive>Delete</Menu.Item>
  </Menu.Content>
</Menu>

Overlay Components

Drawer

import { Drawer } from "@zentrades-ui/components";

<Drawer open={open} onOpenChange={setOpen} side="right">
  <Drawer.Header>
    <Drawer.Title>Settings</Drawer.Title>
  </Drawer.Header>
  <Drawer.Body>
    Content here
  </Drawer.Body>
  <Drawer.Footer>
    <Button onClick={() => setOpen(false)}>Close</Button>
  </Drawer.Footer>
</Drawer>

Popover

import { Popover } from "@zentrades-ui/components";

<Popover>
  <Popover.Trigger asChild>
    <Button>Info</Button>
  </Popover.Trigger>
  <Popover.Content>
    Additional information here
  </Popover.Content>
</Popover>

Tooltip

import { Tooltip } from "@zentrades-ui/components";

<Tooltip content="More information">
  <Button>Hover me</Button>
</Tooltip>

Loading States

Spinner

import { Spinner } from "@zentrades-ui/components";

<Spinner />
<Spinner size="sm" />
<Spinner size="lg" />

Skeleton

import { Skeleton } from "@zentrades-ui/components";

<Skeleton width={200} height={20} />
<Skeleton width="100%" height={40} />
<Skeleton variant="circle" width={40} height={40} />

Icons

Icons are available from @zentrades-ui/icons or re-exported from this package:

// Preferred: Direct import from icons package
import { CheckIcon, SearchIcon, IconByName } from "@zentrades-ui/icons";

// Alternative: Import from components (re-exports)
import { CheckIcon, SearchIcon, IconByName } from "@zentrades-ui/components/icons";

Using Individual Icons

import { CheckIcon, ChevronDownIcon } from "@zentrades-ui/icons";

<CheckIcon size="24" />
<ChevronDownIcon size="16" stroke="#666" />

Using IconByName (Dynamic)

import { IconByName } from "@zentrades-ui/icons";

<IconByName name="check" size="24" />
<IconByName name="chevron-down" size="16" />

See @zentrades-ui/icons for the full list of available icons.

Exports

// Main entry - all components
import { Button, Input, ... } from "@zentrades-ui/components";

// Per-component entrypoints (best for smaller bundles)
import { Button } from "@zentrades-ui/components/components/Button";
import { Input } from "@zentrades-ui/components/components/Input";

// Icons (re-exported from @zentrades-ui/icons)
import { CheckIcon, IconByName, iconNames } from "@zentrades-ui/components/icons";

// Theme re-exports
import { ThemeProvider } from "@zentrades-ui/components/theme";

Accessibility

All components are built with accessibility in mind:

  • Full keyboard navigation support
  • ARIA attributes properly applied
  • Focus management for overlays and modals
  • Screen reader announcements for dynamic content

Components are built on Radix UI primitives where applicable.

Notes

  • This package ships compiled output in dist/
  • CSS side effects are included for component styles
  • Requires @zentrades-ui/theme for styling to work correctly