@zuilib/core
v0.0.1
Published
ZUI — A component library that is both effortless and flexible
Maintainers
Readme
@zuilib/core - ZUI Design System
A modern, accessible component library built with Tailwind CSS v4 and Headless UI v2.
For React Hook Form integration, see @zuilib/rhf
Features
- Token-Based Architecture: 2-layer design token system (primitives + semantic tokens)
- Dark Mode Ready: Automatic theme switching with
.darkclass - Accessible: Built on Headless UI v2 primitives
- Tree-Shakeable: Subpath exports for optimal bundle sizes
- TypeScript: Full type safety
- Tailwind CSS v4: Latest styling capabilities
Installation
# In your workspace root
pnpm installAdd to your project's package.json:
{
"dependencies": {
"@zuilib/core": "workspace:*"
}
}Usage
Importing Styles
Import the styles once in your app entry point:
// main.tsx or App.tsx
import '@zuilib/core/styles.css'Importing Components
Components are available via subpath imports:
import Button from '@zuilib/core/button'
import Input from '@zuilib/core/input'
import Checkbox from '@zuilib/core/checkbox'
function MyForm() {
return (
<form>
<Input placeholder="Enter your name" />
<Checkbox label="I agree to terms" />
<Button variant="primary">Submit</Button>
</form>
)
}Available Components
Button
import Button from '@zuilib/core/button'
<Button variant="primary" size="md">Click me</Button>
<Button variant="secondary">Secondary</Button>
<Button variant="destructive">Delete</Button>
<Button variant="outline">Outline</Button>
<Button variant="ghost">Ghost</Button>Props:
variant:'primary' | 'secondary' | 'destructive' | 'outline' | 'ghost'size:'sm' | 'md' | 'lg'fullWidth:boolean
Input
import Input from '@zuilib/core/input'
<Input placeholder="Enter text" />
<Input variant="error" />
<Input variant="success" />Props:
variant:'default' | 'error' | 'success'size:'sm' | 'md' | 'lg'fullWidth:boolean
Textarea
import Textarea from '@zuilib/core/textarea'
<Textarea placeholder="Enter text" rows={4} />
<Textarea resize="none" />Props:
variant:'default' | 'error' | 'success'resize:'none' | 'vertical' | 'horizontal' | 'both'rows:number
Checkbox
import Checkbox from '@zuilib/core/checkbox'
<Checkbox label="Accept terms" description="You must accept to continue" />Switch
import Switch from '@zuilib/core/switch'
<Switch label="Enable notifications" description="Receive email updates" />Select
import Select from '@zuilib/core/select'
<Select>
<option value="1">Option 1</option>
<option value="2">Option 2</option>
</Select>Listbox
import Listbox from '@zuilib/core/listbox'
const [selected, setSelected] = useState('option1')
<Listbox
value={selected}
onChange={setSelected}
options={[
{ value: 'option1', label: 'Option 1' },
{ value: 'option2', label: 'Option 2' },
]}
/>Combobox
import Combobox from '@zuilib/core/combobox'
const [selected, setSelected] = useState(null)
<Combobox
value={selected}
onChange={setSelected}
options={[
{ value: 1, label: 'Wade Cooper' },
{ value: 2, label: 'Arlene Mccoy' },
]}
placeholder="Search..."
/>Radio Group
import RadioGroup from '@zuilib/core/radio-group'
const [plan, setPlan] = useState('startup')
<RadioGroup
value={plan}
onChange={setPlan}
label="Select a plan"
options={[
{ value: 'startup', label: 'Startup', description: 'For small teams' },
{ value: 'business', label: 'Business', description: 'For growing companies' },
]}
/>Fieldset
import Fieldset from '@zuilib/core/fieldset'
<Fieldset legend="Personal Information" description="Please provide your details">
<Input placeholder="Name" />
<Input placeholder="Email" />
</Fieldset>Design Token System
ZUI uses a 2-layer token architecture for maximum flexibility:
Layer 1: Primitive Tokens
Defined in light-tokens.css and dark-tokens.css:
:root {
--primary: #3b82f6;
--background: #ffffff;
--muted: #f4f4f5;
}Layer 2: Semantic Tokens
Defined in theme.css, mapped to primitives:
@theme {
--color-primary: var(--primary);
--color-background: var(--background);
--color-muted: var(--muted);
}Using Tokens in Components
Tailwind utilities automatically use semantic tokens:
<div className="bg-primary text-primary-foreground">
<div className="border-border bg-muted">Content</div>
</div>Dark Mode
Toggle dark mode by adding the .dark class to your root element:
// Toggle function
function toggleDarkMode() {
document.documentElement.classList.toggle('dark')
}
// Or set directly
document.documentElement.classList.add('dark')
document.documentElement.classList.remove('dark')Customizing Tokens
To customize the design system, edit the token files:
- Colors: Edit
src/styles/design/light-tokens.cssanddark-tokens.css - Semantic Mappings: Edit
src/styles/design/theme.css - Animations: Edit
src/styles/design/keyframes.cssandanimations.css
Example - Change primary color:
/* src/styles/design/light-tokens.css */
:root {
--primary: #8b5cf6; /* Changed from blue to purple */
}Architecture
zui/
├── src/
│ ├── styles/
│ │ ├── index.css # Main entry point
│ │ └── design/
│ │ ├── theme.css # Semantic token mappings
│ │ ├── light-tokens.css # Light mode primitives
│ │ ├── dark-tokens.css # Dark mode overrides
│ │ ├── keyframes.css # Animation keyframes
│ │ ├── animations.css # Animation utilities
│ │ └── base.css # Base element styles
│ ├── button.tsx
│ ├── input.tsx
│ ├── textarea.tsx
│ ├── checkbox.tsx
│ ├── switch.tsx
│ ├── select.tsx
│ ├── listbox.tsx
│ ├── combobox.tsx
│ ├── radio-group.tsx
│ └── fieldset.tsx
└── package.jsonImport Pattern
ZUI uses subpath exports for tree-shaking:
// ✅ Correct - only imports what you need
import Button from '@zuilib/core/button'
import Input from '@zuilib/core/input'
// ❌ Wrong - named exports not supported
import { Button } from 'zui'TypeScript
All components are fully typed with proper prop types and generics where applicable.
License
MIT
