@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/tokensStyles
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/themefor styling to work correctly
