Composable, headless UI components and utilities built for flexibility and great developer experience.
Documentation · Getting Started · Packages
Building UI components from scratch is tedious. Pre-styled component libraries lock you into their design system. Zayne UI gives you the best of both worlds: fully functional, accessible components that you style however you want.
Headless. Composable. TypeScript-first. Zero style opinions.
import { Switch } from "@zayne-labs/ui-react/common/switch";
export default function App() {
const status = "loading";
return (
<Switch.Root value={status}>
<Switch.Match when="loading">
<div>Loading...</div>
</Switch.Match>
<Switch.Match when="error">
<div>Something went wrong</div>
</Switch.Match>
<Switch.Default>
<div>Content loaded!</div>
</Switch.Default>
</Switch.Root>
);
}Bring your own styles. No CSS to override, no design tokens to fight with.
import { Card } from "@zayne-labs/ui-react/ui/card";
<Card.Root className="flex flex-col gap-4">
<Card.Header>
<Card.Title>Your Title</Card.Title>
</Card.Header>
<Card.Content>Your content here</Card.Content>
</Card.Root>;Build complex UIs from simple, reusable pieces.
import { For } from "@zayne-labs/ui-react/common/for";
import { Show } from "@zayne-labs/ui-react/common/show";
<For each={users} fallback={<p>No users found</p>}>
{(user) => (
<div key={user.id}>
<Show when={user.isActive} fallback={<span>Inactive</span>}>
<span>Active</span>
</Show>
{user.name}
</div>
)}
</For>;Full type safety and inference everywhere.
import { Await } from "@zayne-labs/ui-react/common/await";
// Fully typed data and error
<Await promise={fetchUser()}>
{({ data, error }) => (
<Show when={error} fallback={<div>{data.name}</div>}>
<div>Error: {error.message}</div>
</Show>
)}
</Await>;Write UI logic the way you think about it.
import { Switch } from "@zayne-labs/ui-react/common/switch";
<Switch.Root value={userRole}>
<Switch.Match when="admin">
<AdminDashboard />
</Switch.Match>
<Switch.Match when="user">
<UserDashboard />
</Switch.Match>
<Switch.Default>
<GuestView />
</Switch.Default>
</Switch.Root>;Graceful error handling built-in.
import { ErrorBoundary } from "@zayne-labs/ui-react/common/error-boundary";
<ErrorBoundary fallback={(error) => <div>Something went wrong: {error.message}</div>}>
<YourComponent />
</ErrorBoundary>;Render content anywhere in the DOM tree.
import { Teleport } from "@zayne-labs/ui-react/common/teleport";
<Teleport to="body">
<Modal />
</Teleport>;And so much more
See the full documentation for the complete list of components and features.
Headless UI components for common interface patterns:
- Card - Composable card layouts with header, content, and footer sections
- Carousel - Customizable slideshow component with navigation controls
- DragScroll - Add drag-to-scroll behavior to any container
- DropZone - File upload with drag-and-drop support and validation
- Form - Powerful form handling with validation (wrapper around react-hook-form)
Utility components for declarative UI patterns:
- Await - Handle async states declaratively with loading, error, and success states
- ClientGate - Client-side only rendering guard for SSR apps
- ErrorBoundary - Graceful error handling with fallback UI
- For - List rendering with empty states and keyed items
- Presence - Animation presence detection for enter/exit transitions
- Show - Conditional rendering with fallback support
- Slot - Component composition with slots for flexible layouts
- SuspenseWithBoundary - Combined Suspense and ErrorBoundary for async components
- Switch - Pattern matching for conditional rendering with multiple cases
- Teleport - Portal-based content teleportation to any DOM node
npm install @zayne-labs/ui-reactimport { For } from "@zayne-labs/ui-react/common/for";
import { Switch } from "@zayne-labs/ui-react/common/switch";
import { Card } from "@zayne-labs/ui-react/ui/card";
// Declarative conditional rendering
<Switch.Root value={status}>
<Switch.Match when="loading">Loading...</Switch.Match>
<Switch.Match when="error">Error occurred</Switch.Match>
<Switch.Default>Content loaded!</Switch.Default>
</Switch.Root>;
// List rendering with fallback
<For each={users} fallback={<p>No users found</p>}>
{(user) => <div key={user.id}>{user.name}</div>}
</For>;
// Composable card component
<Card.Root>
<Card.Header>
<Card.Title>Card Title</Card.Title>
</Card.Header>
<Card.Content>Your content here</Card.Content>
</Card.Root>;<script type="module">
import { Switch } from "https://esm.run/@zayne-labs/ui-react@latest/common/switch";
</script>- Headless - Complete styling freedom, no CSS to override
- TypeScript-first - Full type inference and safety everywhere
- Composable - Build complex UIs from simple, reusable pieces
- Tree-shakeable - Only bundle what you use
- Framework-ready - React now, more frameworks coming soon
- Zero dependencies - Built on top of @zayne-labs/toolkit
React implementation of the UI library. More framework adapters coming in the future.
This is a monorepo managed with pnpm and Turborepo.
# Install dependencies
pnpm install
# Build all packages
pnpm build
# Run development mode
pnpm dev:react
# Run docs site
pnpm dev:docs
# Run dev playground
pnpm dev:dev
# Lint
pnpm lint:eslint
# Type check
pnpm lint:type-check
# Format code
pnpm lint:formatContributions are welcome! Check out the contributing guidelines to get started.
MIT © Ryan Zayne
