- Replaced font references in globals.css to use DM Sans and JetBrains Mono for improved typography consistency. - Adjusted various components to utilize the new font styles, enhancing visual hierarchy and readability. - Updated layout properties in AppShell and Sidebar for better alignment and spacing. - Enhanced button styles to include a new subtle variant for improved UI flexibility. - Refactored SearchFilterBar to support active filter display, improving user interaction experience. - Made minor adjustments to the DashboardView and landing page components for better visual consistency.
Atomic UI Component Library
This directory contains the atomic UI components for the customer portal application. These components are built with accessibility, consistency, and reusability in mind.
Core Components
Button
A versatile button component with multiple variants, sizes, and states.
import { Button } from "@/components/atoms";
// Basic usage
<Button>Click me</Button>
// With variants and sizes
<Button variant="destructive" size="lg">Delete</Button>
// With loading state
<Button loading loadingText="Saving...">Save</Button>
// With icons
<Button leftIcon={<PlusIcon />}>Add Item</Button>
// As a link
<Button as="a" href="/dashboard">Go to Dashboard</Button>
Props:
variant: "default" | "destructive" | "outline" | "secondary" | "ghost" | "link"size: "xs" | "sm" | "default" | "lg" | "xl"loading: booleanloadingText: stringleftIcon,rightIcon: React.ReactNodeas: "button" | "a" (for polymorphic behavior)
Input
Enhanced input component with validation states and accessibility features.
import { Input } from "@/components/atoms";
// Basic usage
<Input placeholder="Enter your name" />
// With validation states
<Input variant="error" error="This field is required" />
<Input variant="success" />
// With icons
<Input leftIcon={<SearchIcon />} placeholder="Search..." />
// With label and helper text
<Input
label="Email Address"
required
helperText="We'll never share your email"
/>
Props:
variant: "default" | "error" | "success" | "warning"size: "sm" | "default" | "lg"leftIcon,rightIcon: React.ReactNodeerror: stringhelperText: stringlabel: stringrequired: boolean
FormField
Combines Label, Input, and ErrorMessage for complete form fields.
import { FormField } from "@/components/molecules";
<FormField
label="Email Address"
type="email"
required
error={errors.email}
helperText="We'll never share your email"
/>;
Label
Accessible label component with required field indicators.
import { Label } from "@/components/atoms";
<Label htmlFor="email" required>
Email Address
</Label>;
Status & Feedback Components
StatusPill
Displays status information with consistent styling.
import { StatusPill } from "@/components/ui";
<StatusPill variant="success" label="Active" />
<StatusPill variant="error" dot>Failed</StatusPill>
<StatusPill variant="warning" icon={<ClockIcon />}>Pending</StatusPill>
Props:
variant: "success" | "warning" | "info" | "error" | "neutral" | "primary" | "secondary"size: "sm" | "default" | "lg"dot: booleanicon: React.ReactNode
Badge
General-purpose badge component for labels and status indicators.
import { Badge } from "@/components/ui";
<Badge variant="success">New</Badge>
<Badge variant="outline" removable onRemove={() => {}}>Tag</Badge>
<Badge dot variant="error">Critical</Badge>
Props:
variant: "default" | "secondary" | "success" | "warning" | "error" | "info" | "outline" | "ghost"size: "sm" | "default" | "lg"dot: booleanicon: React.ReactNoderemovable: booleanonRemove: () => void
LoadingSpinner
Accessible loading spinner with multiple sizes and variants.
import { LoadingSpinner, CenteredLoadingSpinner } from "@/components/ui";
<LoadingSpinner size="lg" />
<CenteredLoadingSpinner label="Loading data..." />
Props:
size: "xs" | "sm" | "default" | "lg" | "xl"variant: "default" | "white" | "gray" | "current"label: string (for accessibility)
ErrorState
Displays error states with optional retry functionality.
import { ErrorState, NetworkErrorState } from "@/components/ui";
<ErrorState
title="Something went wrong"
message="Please try again later"
onRetry={() => refetch()}
/>
<NetworkErrorState onRetry={() => refetch()} />
Props:
title: stringmessage: stringonRetry: () => voidvariant: "page" | "card" | "inline"
EmptyState
Displays empty states with optional actions.
import { EmptyState, NoDataEmptyState } from "@/components/ui";
<EmptyState
title="No items found"
description="Get started by creating your first item"
action={{
label: "Create Item",
onClick: () => createItem()
}}
/>
<NoDataEmptyState />
Form Validation with Zod
The application uses Zod for type-safe form validation. Use the useZodForm hook for consistent form handling:
import { useZodForm } from "@/core/forms";
import { loginRequestSchema, type LoginRequest } from "@customer-portal/domain/auth";
function MyForm() {
const { values, errors, touched, isSubmitting, setValue, setTouchedField, handleSubmit } =
useZodForm({
schema: loginRequestSchema,
initialValues: {
email: "",
password: "",
},
onSubmit: async (data: LoginRequest) => {
// Handle form submission
await submitLogin(data);
},
});
return (
<form onSubmit={handleSubmit}>
<FormField error={touched.email ? errors.email : undefined}>
<Input
value={values.email}
onChange={e => setValue("email", e.target.value)}
onBlur={() => setTouchedField("email")}
/>
</FormField>
<Button type="submit" disabled={isSubmitting}>
Submit
</Button>
</form>
);
}
Available Zod schemas in @customer-portal/domain:
loginRequestSchema- Login request validation (shared domain schema)signupFormSchema- User registrationprofileEditFormSchema- Profile updatesaddressFormSchema- Address validationpasswordResetFormSchema- Password reset flows
Design Principles
Accessibility
- All components include proper ARIA attributes
- Focus management and keyboard navigation
- Screen reader support with semantic HTML
- Color contrast compliance
Consistency
- Unified design tokens through CSS variables
- Consistent spacing and typography
- Standardized color palette
- Predictable component APIs
Flexibility
- Polymorphic components (Button as link/button)
- Composable architecture
- Customizable through className prop
- Variant-based styling with class-variance-authority
Performance
- Tree-shakeable exports
- Minimal bundle impact
- Efficient re-renders with forwardRef
- Optimized for production builds
Usage Guidelines
-
Import from the index file for better tree-shaking:
import { Button, Input, StatusPill } from "@/components/ui"; -
Use semantic variants that match the intent:
<Button variant="destructive">Delete</Button> // Not variant="red" -
Provide accessibility labels for interactive elements:
<Button aria-label="Close dialog">×</Button> -
Combine components for complex UI patterns:
<FormField label="Search" leftIcon={<SearchIcon />} rightIcon={loading && <LoadingSpinner size="sm" />} /> -
Use Zod validation for consistent form handling:
const { values, errors, setValue } = useZodForm({ schema: emailFormSchema, initialValues: { email: "" }, onSubmit: handleSubmit, });
Contributing
When adding new components:
- Follow the existing patterns and conventions
- Include proper TypeScript types
- Add accessibility features
- Use class-variance-authority for variants
- Export from the index file
- Update this README with usage examples