Skip to content

UI Components

Cosella’s UI component library provides accessible, customizable components built on Radix UI primitives.

Terminal window
pnpm add @cosella/ui
import { Button, Card, Input, Alert } from '@cosella/ui';
function App() {
return (
<Card>
<Alert variant="info" title="Welcome">
This is an info alert.
</Alert>
<Input placeholder="Enter your email" />
<Button variant="primary">Submit</Button>
</Card>
);
}

All components live in packages/ui/src/ and are exported from @cosella/ui.

A customizable button component with multiple variants.

import { Button } from '@cosella/ui';
<Button variant="primary" size="lg">
Get Started
</Button>

Props:

PropTypeDefaultDescription
variant'primary' | 'outline' | 'secondary' | 'ghost' | 'destructive' | 'link''primary'Button variant
size'xs' | 'sm' | 'default' | 'lg' | 'icon-xs' | 'icon-sm' | 'icon' | 'icon-lg''default'Button size
asChildbooleanfalseRender as child element
isLoadingbooleanfalseShow loading spinner

A status badge component.

import { Badge } from '@cosella/ui';
<Badge variant="success">Active</Badge>
<Badge variant="danger">Failed</Badge>
<Badge variant="warning">Pending</Badge>

Variants: blue, green, red, amber, purple, primary

A notification component with multiple variants.

import { Alert } from '@cosella/ui';
<Alert
variant="success"
title="Success"
description="Your changes have been saved."
dismissible
onDismiss={() => {}}
/>

Variants: info, success, warning, danger

A CSS-only hover tooltip.

import { Tooltip } from '@cosella/ui';
<Tooltip content="This is a tooltip">
<Button>Hover me</Button>
</Tooltip>

A styled input with icon support.

import { Input } from '@cosella/ui';
import { Mail } from 'lucide-react';
<Input
leftIcon={Mail}
placeholder="Enter your email"
error="Please enter a valid email"
/>

Props:

PropTypeDescription
leftIconLucideIconIcon on the left
rightIconLucideIconIcon on the right
errorstringError message to display

A styled textarea.

import { Textarea } from '@cosella/ui';
<Textarea placeholder="Enter your message" rows={4} />

A styled select dropdown.

import { Select } from '@cosella/ui';
<Select
options={[
{ value: '1', label: 'Option 1' },
{ value: '2', label: 'Option 2' },
]}
placeholder="Select an option"
/>

A styled checkbox.

import { Checkbox } from '@cosella/ui';
<Checkbox label="I agree to the terms" />

A styled radio button.

import { Radio } from '@cosella/ui';
<Radio name="option" value="1" label="Option 1" />

A toggle switch.

import { Switch } from '@cosella/ui';
<Switch label="Enable notifications" />

A form label.

import { Label } from '@cosella/ui';
<Label>Email Address</Label>

A multi-select dropdown.

import { MultiSelect } from '@cosella/ui';
<MultiSelect
options={[
{ value: '1', label: 'Option 1' },
{ value: '2', label: 'Option 2' },
]}
placeholder="Select options"
/>

A flexible card container with sub-components.

import { Card, CardHeader, CardTitle, CardContent, CardFooter } from '@cosella/ui';
<Card>
<CardHeader>
<CardTitle>Card Title</CardTitle>
</CardHeader>
<CardContent>
<p>Card content goes here.</p>
</CardContent>
<CardFooter>
<Button>Action</Button>
</CardFooter>
</Card>

A tab navigation component.

import { Tabs } from '@cosella/ui';
<Tabs
tabs={[
{ key: 'overview', label: 'Overview' },
{ key: 'settings', label: 'Settings' },
]}
value={activeTab}
onChange={setActiveTab}
/>

A responsive modal dialog.

import { Modal, ModalHeader, ModalTitle, ModalBody, ModalFooter } from '@cosella/ui';
<Modal open={isOpen} onClose={() => setIsOpen(false)} size="md">
<ModalHeader>
<ModalTitle>Modal Title</ModalTitle>
</ModalHeader>
<ModalBody>
<p>Modal content goes here.</p>
</ModalBody>
<ModalFooter>
<Button variant="outline" onClick={() => setIsOpen(false)}>
Cancel
</Button>
<Button variant="primary">Confirm</Button>
</ModalFooter>
</Modal>

A dropdown menu.

import { Menu, MenuItem, MenuDivider, MenuLabel } from '@cosella/ui';
<Menu>
<MenuLabel>Actions</MenuLabel>
<MenuItem>Edit</MenuItem>
<MenuItem>Duplicate</MenuItem>
<MenuDivider />
<MenuItem>Delete</MenuItem>
</Menu>

A powerful data table with search, sort, and pagination.

import { DataTable, type Column } from '@cosella/ui';
const columns: Column<User>[] = [
{ key: 'name', header: 'Name', sortable: true },
{ key: 'email', header: 'Email' },
{ key: 'role', header: 'Role' },
];
<DataTable
columns={columns}
data={users}
searchPlaceholder="Search users..."
searchKeys={(row) => [row.name, row.email]}
pageSize={10}
/>

Pagination controls for data tables.

import { TablePagination } from '@cosella/ui';
<TablePagination
pageIndex={0}
pageSize={10}
pageCount={5}
onPageChange={(page) => setPageIndex(page)}
/>

A toast notification system.

import { Toaster, toast } from '@cosella/ui';
// In your app root
<Toaster />
// Trigger a toast
toast.success('Changes saved');
toast.error('Something went wrong');

Loading skeleton placeholders.

import { Skeleton, SkeletonText, SkeletonAvatar, SkeletonCard, SkeletonTable } from '@cosella/ui';
<Skeleton className="h-4 w-32" />
<SkeletonText lines={3} />
<SkeletonAvatar size="md" />
<SkeletonCard />
<SkeletonTable rows={5} />

A full-page loading spinner.

import { FullScreenLoader } from '@cosella/ui';
<FullScreenLoader />

A 404 page.

import { NotFoundPage } from '@cosella/ui';
<NotFoundPage />

An error page.

import { CrashPage } from '@cosella/ui';
<CrashPage />

A utility for merging Tailwind classes.

import { cn } from '@cosella/ui';
<div className={cn(
'base-class',
isActive && 'active-class',
className,
)} />

All components accept className prop for styling:

<Button className="my-custom-class">
Custom Button
</Button>
import { Button } from '@cosella/ui';
// Use Tailwind classes with design tokens
<Button className="bg-brand-500 hover:bg-brand-600">
Brand Button
</Button>

All components follow WAI-ARIA patterns:

  • Keyboard navigation
  • Screen reader support
  • Focus management
  • ARIA attributes

View component stories in Storybook:

Terminal window
pnpm --filter @cosella/storybook dev