📖 Looking for karrio's legacy docs? Visit docs.karrio.io

UI Components & Design System

Insiders
Enterprise

Build beautiful, consistent, and accessible user interfaces for your Karrio Apps using our comprehensive component library and design system.

Overview

Karrio Apps provide access to a rich set of pre-built UI components that follow our design system principles. These components are built with React, TypeScript, and Tailwind CSS, ensuring consistency across all apps in the platform.

Component Library

Core Components

Button

The Button component supports multiple variants, sizes, and states:

1import { Button } from "@karrio/ui"; 2 3export default function MyApp() { 4 return ( 5 <div className="space-y-4"> 6 {/* Primary button */} 7 <Button 8 variant="primary" 9 size="md" 10 onClick={() => console.log("Clicked!")} 11 > 12 Primary Action 13 </Button> 14 15 {/* Secondary button */} 16 <Button variant="secondary" size="sm"> 17 Secondary Action 18 </Button> 19 20 {/* Danger button */} 21 <Button variant="danger" size="lg" disabled> 22 Dangerous Action 23 </Button> 24 25 {/* Loading state */} 26 <Button variant="primary" loading> 27 Loading... 28 </Button> 29 30 {/* Icon button */} 31 <Button variant="ghost" size="sm" icon="plus"> 32 Add Item 33 </Button> 34 </div> 35 ); 36}

Props:

  • variant: primary | secondary | danger | ghost | outline
  • size: xs | sm | md | lg | xl
  • loading: boolean
  • disabled: boolean
  • icon: string (icon name)
  • fullWidth: boolean

Input & Form Controls

1import { Input, Select, Textarea, Checkbox, Radio } from "@karrio/ui"; 2 3export default function FormExample() { 4 const [formData, setFormData] = useState({ 5 name: "", 6 email: "", 7 priority: "medium", 8 description: "", 9 notifications: false, 10 type: "shipment", 11 }); 12 13 return ( 14 <form className="space-y-6"> 15 {/* Text Input */} 16 <Input 17 label="Full Name" 18 placeholder="Enter your full name" 19 value={formData.name} 20 onChange={(value) => setFormData({ ...formData, name: value })} 21 required 22 error={!formData.name ? "Name is required" : undefined} 23 /> 24 25 {/* Email Input */} 26 <Input 27 type="email" 28 label="Email Address" 29 placeholder="you@example.com" 30 value={formData.email} 31 onChange={(value) => setFormData({ ...formData, email: value })} 32 leftIcon="mail" 33 required 34 /> 35 36 {/* Select Dropdown */} 37 <Select 38 label="Priority Level" 39 value={formData.priority} 40 onChange={(value) => setFormData({ ...formData, priority: value })} 41 options={[ 42 { value: "low", label: "Low Priority" }, 43 { value: "medium", label: "Medium Priority" }, 44 { value: "high", label: "High Priority" }, 45 { value: "urgent", label: "Urgent" }, 46 ]} 47 /> 48 49 {/* Textarea */} 50 <Textarea 51 label="Description" 52 placeholder="Describe the task..." 53 value={formData.description} 54 onChange={(value) => setFormData({ ...formData, description: value })} 55 rows={4} 56 /> 57 58 {/* Checkbox */} 59 <Checkbox 60 label="Enable notifications" 61 checked={formData.notifications} 62 onChange={(checked) => 63 setFormData({ ...formData, notifications: checked }) 64 } 65 /> 66 67 {/* Radio Group */} 68 <div className="space-y-2"> 69 <label className="text-sm font-medium">Type</label> 70 <div className="space-y-2"> 71 <Radio 72 name="type" 73 value="shipment" 74 label="Shipment" 75 checked={formData.type === "shipment"} 76 onChange={(value) => setFormData({ ...formData, type: value })} 77 /> 78 <Radio 79 name="type" 80 value="order" 81 label="Order" 82 checked={formData.type === "order"} 83 onChange={(value) => setFormData({ ...formData, type: value })} 84 /> 85 </div> 86 </div> 87 </form> 88 ); 89}

Cards & Containers

1import { Card, Panel, Section } from "@karrio/ui"; 2 3export default function ContainerExample() { 4 return ( 5 <div className="space-y-6"> 6 {/* Basic Card */} 7 <Card> 8 <Card.Header> 9 <Card.Title>Shipping Summary</Card.Title> 10 <Card.Subtitle>Last 30 days</Card.Subtitle> 11 </Card.Header> 12 <Card.Content> 13 <div className="grid grid-cols-3 gap-4"> 14 <div className="text-center"> 15 <div className="text-2xl font-bold">152</div> 16 <div className="text-sm text-gray-500">Total Shipments</div> 17 </div> 18 <div className="text-center"> 19 <div className="text-2xl font-bold">$2,451</div> 20 <div className="text-sm text-gray-500">Total Cost</div> 21 </div> 22 <div className="text-center"> 23 <div className="text-2xl font-bold">98.5%</div> 24 <div className="text-sm text-gray-500">Success Rate</div> 25 </div> 26 </div> 27 </Card.Content> 28 <Card.Footer> 29 <Button variant="outline" size="sm"> 30 View Details 31 </Button> 32 </Card.Footer> 33 </Card> 34 35 {/* Panel with collapsible sections */} 36 <Panel title="Configuration" collapsible defaultOpen> 37 <Section title="API Settings"> 38 <div className="space-y-4"> 39 <Input 40 label="API Endpoint" 41 defaultValue="https://api.example.com" 42 /> 43 <Input 44 label="API Key" 45 type="password" 46 placeholder="Enter your API key" 47 /> 48 </div> 49 </Section> 50 <Section title="Notification Settings"> 51 <div className="space-y-2"> 52 <Checkbox label="Email notifications" defaultChecked /> 53 <Checkbox label="SMS notifications" /> 54 <Checkbox label="Webhook notifications" defaultChecked /> 55 </div> 56 </Section> 57 </Panel> 58 </div> 59 ); 60}

Data Display Components

Table

1import { Table, Badge, Avatar } from "@karrio/ui"; 2 3export default function ShipmentTable() { 4 const shipments = [ 5 { 6 id: "SH001", 7 recipient: "John Doe", 8 status: "delivered", 9 carrier: "FedEx", 10 cost: "$15.99", 11 date: "2024-01-15", 12 }, 13 { 14 id: "SH002", 15 recipient: "Jane Smith", 16 status: "in_transit", 17 carrier: "UPS", 18 cost: "$22.50", 19 date: "2024-01-14", 20 }, 21 ]; 22 23 const columns = [ 24 { 25 header: "Shipment ID", 26 accessor: "id" as const, 27 cell: (value: string) => ( 28 <code className="text-sm bg-gray-100 px-2 py-1 rounded">{value}</code> 29 ), 30 }, 31 { 32 header: "Recipient", 33 accessor: "recipient" as const, 34 cell: (value: string) => ( 35 <div className="flex items-center space-x-2"> 36 <Avatar name={value} size="sm" /> 37 <span>{value}</span> 38 </div> 39 ), 40 }, 41 { 42 header: "Status", 43 accessor: "status" as const, 44 cell: (value: string) => ( 45 <Badge variant={value === "delivered" ? "success" : "warning"}> 46 {value.replace("_", " ")} 47 </Badge> 48 ), 49 }, 50 { 51 header: "Carrier", 52 accessor: "carrier" as const, 53 }, 54 { 55 header: "Cost", 56 accessor: "cost" as const, 57 cell: (value: string) => <span className="font-medium">{value}</span>, 58 }, 59 { 60 header: "Date", 61 accessor: "date" as const, 62 cell: (value: string) => ( 63 <span className="text-gray-500"> 64 {new Date(value).toLocaleDateString()} 65 </span> 66 ), 67 }, 68 ]; 69 70 return ( 71 <Table 72 data={shipments} 73 columns={columns} 74 searchable 75 sortable 76 pagination 77 emptyMessage="No shipments found" 78 onRowClick={(shipment) => console.log("Clicked:", shipment)} 79 /> 80 ); 81}

Lists & Grids

1import { List, Grid, StatusIndicator } from "@karrio/ui"; 2 3export default function DataDisplayExample() { 4 const tasks = [ 5 { id: 1, title: "Process refund", status: "pending", priority: "high" }, 6 { 7 id: 2, 8 title: "Update tracking", 9 status: "completed", 10 priority: "medium", 11 }, 12 { id: 3, title: "Generate report", status: "in_progress", priority: "low" }, 13 ]; 14 15 return ( 16 <div className="space-y-8"> 17 {/* List View */} 18 <div> 19 <h3 className="font-semibold mb-4">Task List</h3> 20 <List> 21 {tasks.map((task) => ( 22 <List.Item key={task.id}> 23 <div className="flex items-center justify-between"> 24 <div className="flex items-center space-x-3"> 25 <StatusIndicator status={task.status} /> 26 <span className="font-medium">{task.title}</span> 27 </div> 28 <Badge 29 variant={task.priority === "high" ? "danger" : "default"} 30 > 31 {task.priority} 32 </Badge> 33 </div> 34 </List.Item> 35 ))} 36 </List> 37 </div> 38 39 {/* Grid View */} 40 <div> 41 <h3 className="font-semibold mb-4">Card Grid</h3> 42 <Grid cols={3} gap={4}> 43 {tasks.map((task) => ( 44 <Card key={task.id} className="p-4"> 45 <div className="flex items-center justify-between mb-2"> 46 <StatusIndicator status={task.status} /> 47 <Badge 48 variant={task.priority === "high" ? "danger" : "default"} 49 > 50 {task.priority} 51 </Badge> 52 </div> 53 <h4 className="font-medium">{task.title}</h4> 54 </Card> 55 ))} 56 </Grid> 57 </div> 58 </div> 59 ); 60}

Tabs

1import { Tabs, TabPanel } from "@karrio/ui"; 2 3export default function AppTabs() { 4 return ( 5 <Tabs defaultValue="overview"> 6 <Tabs.List> 7 <Tabs.Trigger value="overview">Overview</Tabs.Trigger> 8 <Tabs.Trigger value="shipments">Shipments</Tabs.Trigger> 9 <Tabs.Trigger value="analytics">Analytics</Tabs.Trigger> 10 <Tabs.Trigger value="settings">Settings</Tabs.Trigger> 11 </Tabs.List> 12 13 <TabPanel value="overview"> 14 <div className="py-6"> 15 <h2 className="text-xl font-semibold mb-4">Overview</h2> 16 <p>Welcome to your shipping dashboard overview.</p> 17 </div> 18 </TabPanel> 19 20 <TabPanel value="shipments"> 21 <div className="py-6"> 22 <h2 className="text-xl font-semibold mb-4">Shipments</h2> 23 <ShipmentTable /> 24 </div> 25 </TabPanel> 26 27 <TabPanel value="analytics"> 28 <div className="py-6"> 29 <h2 className="text-xl font-semibold mb-4">Analytics</h2> 30 <p>View your shipping analytics and insights.</p> 31 </div> 32 </TabPanel> 33 34 <TabPanel value="settings"> 35 <div className="py-6"> 36 <h2 className="text-xl font-semibold mb-4">Settings</h2> 37 <p>Configure your app settings.</p> 38 </div> 39 </TabPanel> 40 </Tabs> 41 ); 42}
1import { Breadcrumbs } from "@karrio/ui"; 2 3export default function AppBreadcrumbs() { 4 return ( 5 <Breadcrumbs 6 items={[ 7 { label: "Dashboard", href: "/dashboard" }, 8 { label: "Apps", href: "/apps" }, 9 { label: "Shipping Manager", href: "/apps/shipping-manager" }, 10 { label: "Settings" }, // Current page (no href) 11 ]} 12 /> 13 ); 14}

Feedback Components

Toast Notifications

1import { useToast } from "@karrio/ui"; 2 3export default function NotificationExample() { 4 const { toast } = useToast(); 5 6 const showToast = (type: string) => { 7 switch (type) { 8 case "success": 9 toast.success("Shipment created successfully!"); 10 break; 11 case "error": 12 toast.error("Failed to create shipment. Please try again."); 13 break; 14 case "warning": 15 toast.warning("Rate limit approaching. Consider upgrading your plan."); 16 break; 17 case "info": 18 toast.info("New carrier integration available."); 19 break; 20 } 21 }; 22 23 return ( 24 <div className="space-x-4"> 25 <Button onClick={() => showToast("success")}>Success Toast</Button> 26 <Button onClick={() => showToast("error")}>Error Toast</Button> 27 <Button onClick={() => showToast("warning")}>Warning Toast</Button> 28 <Button onClick={() => showToast("info")}>Info Toast</Button> 29 </div> 30 ); 31}

Loading States

1import { Spinner, Skeleton, LoadingOverlay } from "@karrio/ui"; 2 3export default function LoadingExample() { 4 const [loading, setLoading] = useState(false); 5 6 return ( 7 <div className="space-y-8"> 8 {/* Spinner */} 9 <div className="flex items-center space-x-2"> 10 <Spinner size="sm" /> 11 <span>Loading...</span> 12 </div> 13 14 {/* Skeleton Loading */} 15 <div className="space-y-4"> 16 <Skeleton height="h-4" width="w-3/4" /> 17 <Skeleton height="h-4" width="w-1/2" /> 18 <Skeleton height="h-32" width="w-full" /> 19 </div> 20 21 {/* Loading Overlay */} 22 <div className="relative"> 23 <LoadingOverlay visible={loading} /> 24 <Card className="p-6"> 25 <h3 className="font-semibold mb-4">Data Processing</h3> 26 <p> 27 This content will be covered by loading overlay when processing. 28 </p> 29 <Button onClick={() => setLoading(!loading)} className="mt-4"> 30 Toggle Loading 31 </Button> 32 </Card> 33 </div> 34 </div> 35 ); 36}

Alerts & Banners

1import { Alert, Banner } from "@karrio/ui"; 2 3export default function AlertExample() { 4 return ( 5 <div className="space-y-4"> 6 {/* Alert Messages */} 7 <Alert variant="success" title="Success"> 8 Your shipment has been created and is ready for pickup. 9 </Alert> 10 11 <Alert variant="error" title="Error" dismissible> 12 Failed to connect to carrier API. Please check your credentials. 13 </Alert> 14 15 <Alert variant="warning" title="Warning"> 16 Your API rate limit is at 80%. Consider upgrading your plan. 17 </Alert> 18 19 <Alert variant="info" title="Information"> 20 New shipping rates are available. Update your preferences in settings. 21 </Alert> 22 23 {/* Banner (full-width) */} 24 <Banner variant="upgrade" dismissible> 25 <div className="flex items-center justify-between"> 26 <div> 27 <strong>Upgrade to Pro</strong> to unlock advanced analytics and 28 unlimited shipments. 29 </div> 30 <Button variant="primary" size="sm"> 31 Upgrade Now 32 </Button> 33 </div> 34 </Banner> 35 </div> 36 ); 37}
1import { Modal, ConfirmDialog } from "@karrio/ui"; 2 3export default function ModalExample() { 4 const [isOpen, setIsOpen] = useState(false); 5 const [showConfirm, setShowConfirm] = useState(false); 6 7 const handleDelete = () => { 8 setShowConfirm(true); 9 }; 10 11 const confirmDelete = () => { 12 console.log("Item deleted"); 13 setShowConfirm(false); 14 }; 15 16 return ( 17 <> 18 <Button onClick={() => setIsOpen(true)}>Open Modal</Button> 19 20 <Modal 21 open={isOpen} 22 onClose={() => setIsOpen(false)} 23 title="Create New Shipment" 24 size="lg" 25 > 26 <Modal.Content> 27 <form className="space-y-4"> 28 <Input label="Recipient Name" placeholder="Enter recipient name" /> 29 <Input 30 label="Tracking Number" 31 placeholder="Enter tracking number" 32 /> 33 <Select 34 label="Carrier" 35 options={[ 36 { value: "fedex", label: "FedEx" }, 37 { value: "ups", label: "UPS" }, 38 { value: "dhl", label: "DHL" }, 39 ]} 40 /> 41 </form> 42 </Modal.Content> 43 <Modal.Footer> 44 <Button variant="outline" onClick={() => setIsOpen(false)}> 45 Cancel 46 </Button> 47 <Button variant="primary" onClick={() => setIsOpen(false)}> 48 Create Shipment 49 </Button> 50 </Modal.Footer> 51 </Modal> 52 53 {/* Confirmation Dialog */} 54 <Button variant="danger" onClick={handleDelete}> 55 Delete Item 56 </Button> 57 58 <ConfirmDialog 59 open={showConfirm} 60 onClose={() => setShowConfirm(false)} 61 onConfirm={confirmDelete} 62 title="Confirm Deletion" 63 message="Are you sure you want to delete this item? This action cannot be undone." 64 confirmText="Delete" 65 cancelText="Cancel" 66 variant="danger" 67 /> 68 </> 69 ); 70}
1import { DropdownMenu } from "@karrio/ui"; 2 3export default function DropdownExample() { 4 return ( 5 <DropdownMenu> 6 <DropdownMenu.Trigger asChild> 7 <Button variant="outline"> 8 Actions 9 <ChevronDownIcon className="ml-2 h-4 w-4" /> 10 </Button> 11 </DropdownMenu.Trigger> 12 <DropdownMenu.Content> 13 <DropdownMenu.Item onClick={() => console.log("Edit")}> 14 <EditIcon className="mr-2 h-4 w-4" /> 15 Edit 16 </DropdownMenu.Item> 17 <DropdownMenu.Item onClick={() => console.log("Duplicate")}> 18 <CopyIcon className="mr-2 h-4 w-4" /> 19 Duplicate 20 </DropdownMenu.Item> 21 <DropdownMenu.Separator /> 22 <DropdownMenu.Item 23 onClick={() => console.log("Delete")} 24 className="text-red-600" 25 > 26 <TrashIcon className="mr-2 h-4 w-4" /> 27 Delete 28 </DropdownMenu.Item> 29 </DropdownMenu.Content> 30 </DropdownMenu> 31 ); 32}

Styling & Theming

Tailwind CSS Integration

All Karrio UI components are built with Tailwind CSS and follow our design system:

Custom styling with Tailwind classes
1<Button 2 className="bg-gradient-to-r from-blue-500 to-purple-600 hover:from-blue-600 hover:to-purple-700" 3> 4 Gradient Button 5</Button> 6 7<Card className="border-l-4 border-l-blue-500 shadow-lg"> 8 <Card.Content className="bg-blue-50 dark:bg-blue-900/20"> 9 Custom styled card with accent border 10 </Card.Content> 11</Card>

CSS Variables & Custom Properties

Access design tokens through CSS variables:

Available design tokens */
1:root { 2 --color-primary: #3b82f6; 3 --color-secondary: #64748b; 4 --color-success: #10b981; 5 --color-warning: #f59e0b; 6 --color-error: #ef4444; 7 8 --spacing-xs: 0.25rem; 9 --spacing-sm: 0.5rem; 10 --spacing-md: 1rem; 11 --spacing-lg: 1.5rem; 12 --spacing-xl: 2rem; 13 14 --border-radius-sm: 0.25rem; 15 --border-radius-md: 0.375rem; 16 --border-radius-lg: 0.5rem; 17} 18 19/* Custom component styling */ 20.my-custom-component { 21 background-color: var(--color-primary); 22 padding: var(--spacing-md); 23 border-radius: var(--border-radius-md); 24}

Dark Mode Support

All components automatically support dark mode:

1export default function ThemedComponent() { 2 return ( 3 <div className="bg-white dark:bg-gray-900 text-gray-900 dark:text-gray-100"> 4 <Card className="border-gray-200 dark:border-gray-700"> 5 <Card.Content> 6 This content adapts to light and dark themes automatically. 7 </Card.Content> 8 </Card> 9 </div> 10 ); 11}

Accessibility

Built-in Accessibility Features

All Karrio UI components include accessibility features:

  • Keyboard Navigation: Full keyboard support with proper focus management
  • Screen Reader Support: ARIA labels and descriptions
  • High Contrast: Meets WCAG contrast requirements
  • Focus Management: Visible focus indicators and logical tab order
Accessibility example
1<form> 2 <Input 3 label="Email Address" 4 id="email" 5 type="email" 6 required 7 aria-describedby="email-error" 8 error="Please enter a valid email address" 9 /> 10 <div id="email-error" role="alert" aria-live="polite"> 11 {/* Error message will be announced by screen readers */} 12 </div> 13</form>

Custom Accessibility

1import { useAnnouncer, useFocusManager } from "@karrio/ui"; 2 3export default function AccessibleComponent() { 4 const { announce } = useAnnouncer(); 5 const { focusFirst, focusLast } = useFocusManager(); 6 7 const handleAction = () => { 8 // Announce status to screen readers 9 announce("Task completed successfully", "polite"); 10 11 // Manage focus programmatically 12 focusFirst('[data-focusable="true"]'); 13 }; 14 15 return ( 16 <div> 17 <Button onClick={handleAction}>Complete Task</Button> 18 <div data-focusable="true" tabIndex={0}> 19 Focusable element 20 </div> 21 </div> 22 ); 23}

Best Practices

Component Composition

✅ Good: Compose components for flexibility
1<Card> 2 <Card.Header> 3 <div className="flex items-center justify-between"> 4 <Card.Title>Shipment Details</Card.Title> 5 <Badge variant="success">Delivered</Badge> 6 </div> 7 </Card.Header> 8 <Card.Content> 9 <div className="space-y-4"> 10 <div className="flex justify-between"> 11 <span className="text-gray-500">Tracking Number:</span> 12 <code>1Z999AA1234567890</code> 13 </div> 14 <div className="flex justify-between"> 15 <span className="text-gray-500">Delivery Date:</span> 16 <span>January 15, 2024</span> 17 </div> 18 </div> 19 </Card.Content> 20</Card> 21 22// ❌ Avoid: Overly complex single components 23<ComplexShipmentCard 24 trackingNumber="1Z999AA1234567890" 25 deliveryDate="2024-01-15" 26 status="delivered" 27 showBadge={true} 28 showActions={false} 29 customStyles={{...}} 30/>

State Management

✅ Good: Use controlled components with proper state management
1export default function ShippingForm() { 2 const [formState, setFormState] = useState({ 3 recipient: "", 4 address: "", 5 carrier: "", 6 }); 7 8 const updateField = (field: string, value: string) => { 9 setFormState((prev) => ({ ...prev, [field]: value })); 10 }; 11 12 return ( 13 <form> 14 <Input 15 label="Recipient" 16 value={formState.recipient} 17 onChange={(value) => updateField("recipient", value)} 18 /> 19 <Input 20 label="Address" 21 value={formState.address} 22 onChange={(value) => updateField("address", value)} 23 /> 24 <Select 25 label="Carrier" 26 value={formState.carrier} 27 onChange={(value) => updateField("carrier", value)} 28 options={carriers} 29 /> 30 </form> 31 ); 32}

Performance Optimization

1import { memo, useMemo, useCallback } from "react"; 2 3// ✅ Good: Memoize expensive operations 4const ShipmentList = memo(({ shipments, onUpdate }) => { 5 const sortedShipments = useMemo(() => { 6 return shipments.sort( 7 (a, b) => 8 new Date(b.created_at).getTime() - new Date(a.created_at).getTime(), 9 ); 10 }, [shipments]); 11 12 const handleUpdate = useCallback( 13 (id, updates) => { 14 onUpdate(id, updates); 15 }, 16 [onUpdate], 17 ); 18 19 return ( 20 <div> 21 {sortedShipments.map((shipment) => ( 22 <ShipmentCard 23 key={shipment.id} 24 shipment={shipment} 25 onUpdate={handleUpdate} 26 /> 27 ))} 28 </div> 29 ); 30});

Next Steps

Resources


Build beautiful, accessible, and consistent user interfaces that users love!