This document covers Datum's component library built on shadcn/ui primitives.
datum-ui is Datum's design system containing:
- Composed components (DataTable, Form)
- Datum-specific variants (Badge, Alert)
- Business logic components (Stepper, Grid)
Future: Will be extracted to @datum/ui npm package for sharing across portals.
app/modules/datum-ui/
├── components/
│ ├── alert/
│ ├── avatar-stack/
│ ├── badge/
│ ├── button/
│ ├── calendar/
│ ├── card/
│ ├── data-table/ # Complex - has own README
│ ├── dialog/
│ ├── dropdown/
│ ├── form/ # Legacy form
│ ├── grid/
│ ├── input-number/
│ ├── input-with-addons/
│ ├── form/ # New form library
│ ├── nprogress/
│ ├── sidebar/
│ ├── stepper/
│ ├── tabs/
│ ├── tag-input/
│ ├── toast/
│ └── tooltip/
├── datum-ui.css
└── index.ts
// Named imports from components
import { Badge, Alert, Button } from '@datum-ui/components';
// Direct component imports (for complex components)
import { DataTable } from '@datum-ui/components/data-table';
import { Form } from '@datum-ui/components/form';
import { Row, Col } from '@datum-ui/components/grid';Full-featured data table with filtering, sorting, and pagination.
import { DataTable } from '@datum-ui/components/data-table';
import { DataTableFilter } from '@datum-ui/components/data-table/features/filter';
const columns = [
{ accessorKey: 'name', header: 'Name' },
{ accessorKey: 'status', header: 'Status' },
];
<DataTable
columns={columns}
data={data}
tableTitle="Organizations"
filterComponent={
<DataTableFilter>
<DataTableFilter.Search filterKey="name" placeholder="Search..." />
<DataTableFilter.Select
filterKey="status"
options={[
{ label: 'Active', value: 'active' },
{ label: 'Inactive', value: 'inactive' },
]}
/>
</DataTableFilter>
}
/>;Features:
- Client-side and server-side filtering
- URL state synchronization
- Sorting with custom labels
- Pagination
- Row actions
- Card mode for mobile
→ Full docs: app/modules/datum-ui/components/data-table/README.md
Compound component form with Conform.js + Zod validation.
import { Form } from '@datum-ui/components/form';
import { z } from 'zod';
const schema = z.object({
name: z.string().min(2),
email: z.string().email(),
});
<Form.Root schema={schema} onSubmit={handleSubmit}>
<Form.Field name="name" label="Name" required>
<Form.Input />
</Form.Field>
<Form.Field name="email" label="Email" required>
<Form.Input type="email" />
</Form.Field>
<Form.Submit>Save</Form.Submit>
</Form.Root>;Features:
- Schema-based validation
- Auto error display
- Loading states
- Multi-step forms
- Field arrays
- Conditional fields
→ Full docs: app/modules/datum-ui/components/form/README.md
→ See also: Forms Guide
Status badges with semantic variants.
import { Badge } from '@datum-ui/components';
<Badge variant="success">Active</Badge>
<Badge variant="warning">Pending</Badge>
<Badge variant="error">Failed</Badge>
<Badge variant="info">Processing</Badge>
<Badge variant="default">Draft</Badge>Alert messages with variants.
import { Alert } from '@datum-ui/components';
<Alert variant="info" title="Information">
This is an informational message.
</Alert>
<Alert variant="warning" title="Warning">
Please review before continuing.
</Alert>
<Alert variant="error" title="Error">
Something went wrong.
</Alert>
<Alert variant="success" title="Success">
Operation completed successfully.
</Alert>Responsive grid layout based on 24-column grid.
import { Row, Col } from '@datum-ui/components/grid';
<Row gutter={16}>
<Col span={24} md={12} lg={6}>
Quarter on large screens
</Col>
<Col span={24} md={12} lg={6}>
Quarter on large screens
</Col>
<Col span={24} md={12} lg={6}>
Quarter on large screens
</Col>
<Col span={24} md={12} lg={6}>
Quarter on large screens
</Col>
</Row>;Breakpoints:
xs: < 576pxsm: ≥ 576pxmd: ≥ 768pxlg: ≥ 992pxxl: ≥ 1200pxxxl: ≥ 1600px
Step indicator for multi-step flows.
import { Stepper } from '@datum-ui/components/stepper';
<Stepper
steps={[
{ id: 'details', label: 'Details' },
{ id: 'config', label: 'Configuration' },
{ id: 'review', label: 'Review' },
]}
currentStep="config"
/>;Toast notifications via Sonner.
import { toast } from 'sonner';
// Success
toast.success('Organization created');
// Error
toast.error('Failed to save');
// With description
toast.success('DNS Zone Created', {
description: 'Your zone is now active.',
});
// Promise toast
toast.promise(saveData(), {
loading: 'Saving...',
success: 'Saved!',
error: 'Failed to save',
});Stacked avatars for showing multiple users.
import { AvatarStack } from '@datum-ui/components';
<AvatarStack
avatars={[
{ name: 'John Doe', src: '/avatars/john.jpg' },
{ name: 'Jane Smith', src: '/avatars/jane.jpg' },
{ name: 'Bob Wilson' }, // Fallback to initials
]}
max={3}
/>;- Component is reusable across portals (cloud-portal, staff-portal)
- Has Datum-specific variants or business logic
- Extends shadcn with additional functionality
- Needs consistent behavior across the ecosystem
- Page-specific component
- Cloud-portal only functionality
- One-off usage
- Contains app-specific business logic
app/modules/datum-ui/components/{component-name}/
├── index.ts # Exports
├── {component}.tsx # Main component
├── {component}.types.ts # TypeScript types (optional)
└── README.md # Documentation (recommended)
// app/modules/datum-ui/components/status-indicator/status-indicator.tsx
import { cn } from '@shadcn/lib/utils';
export interface StatusIndicatorProps {
status: 'online' | 'offline' | 'pending' | 'error';
label?: string;
size?: 'sm' | 'md' | 'lg';
}
const statusColors = {
online: 'bg-green-500',
offline: 'bg-gray-400',
pending: 'bg-yellow-500',
error: 'bg-red-500',
};
const sizes = {
sm: 'h-2 w-2',
md: 'h-3 w-3',
lg: 'h-4 w-4',
};
export function StatusIndicator({
status,
label,
size = 'md',
}: StatusIndicatorProps) {
return (
<div className="flex items-center gap-2">
<span
className={cn(
'rounded-full',
statusColors[status],
sizes[size]
)}
/>
{label && <span className="text-sm">{label}</span>}
</div>
);
}// app/modules/datum-ui/components/status-indicator/index.ts
export { StatusIndicator } from './status-indicator';
export type { StatusIndicatorProps } from './status-indicator';// app/modules/datum-ui/components/index.ts
export * from './status-indicator';Complex components have their own README:
data-table/README.md- DataTable with filteringdata-table/TOOLBAR_GUIDE.md- Toolbar customizationform/README.md- Form librarygrid/README.md- Grid systembadge/README.md- Badge variants
Always check these before using complex components.
- UI Overview - Component hierarchy
- shadcn Rules - Base primitives
- Forms Guide - Form patterns
- Adding New Component