UI Standards Guide for do.dev Application
This document defines the UI/UX standards and patterns to be used consistently across the do.dev application.
Design Principles
- Clarity over Cleverness - Interfaces should be immediately understandable
- Consistency is Key - Same patterns should work the same way everywhere
- Subtle Feedback - Visual feedback should be clear but not distracting
- Performance First - Animations and transitions should be fast and smooth
- Accessibility Always - All interactions must be keyboard and screen-reader friendly
🚨 CRITICAL: Cursor Pointer Rule
ALL clickable elements MUST have cursor-pointer class. NO EXCEPTIONS.
This includes but is not limited to:
- Buttons (all variants)
- Links
- Clickable cards
- Dropdown triggers
- Menu items
- Interactive list items
- Tab buttons
- Modal close buttons
- Any element with an onClick handler
- Any element that performs an action when clicked
Example:
// ✅ CORRECT - Always include cursor-pointer
<button onClick={handleClick} className="cursor-pointer">Click me</button>
<Link href="/page" className="cursor-pointer">Navigate</Link>
<div onClick={selectItem} className="cursor-pointer">Select this</div>
// ❌ WRONG - Missing cursor-pointer
<button onClick={handleClick}>Click me</button>
<Link href="/page">Navigate</Link>
<div onClick={selectItem}>Select this</div>Color Palette
Primary Colors
- Blue: Primary actions and selections
blue-500- Primary blue (#3B82F6)blue-600- Hover state (#2563EB)blue-50- Light background tint
Neutral Colors
- Gray: Text and borders
gray-900- Primary textgray-700- Secondary textgray-500- Tertiary text / placeholdersgray-300- Borders (list items, form inputs)gray-100- Dividersgray-50- Background tints (list items, subtle backgrounds)
Semantic Colors
-
Green: Success states
green-600- Success text/iconsgreen-100- Success backgroundsgreen-800- Success text on light backgrounds
-
Red: Error/Danger states
red-600- Error text/delete actionsred-100- Error backgrounds
Typography
Font Sizes
text-3xl- Page titles (30px)text-xl- Section headers (20px)text-lg- Subsection headers (18px)text-base- Body text (16px)text-sm- Secondary text (14px)text-xs- Labels and metadata (12px)
Font Weights
font-semibold- Headers and emphasisfont-medium- Subheaders and important textfont-normal- Body text
Font Families
font-mono- Code, technical values (domains, IPs, ports)- Default sans-serif for all other text
Component Patterns
Cards
Selectable Cards
Used for items that can be selected (DNS zones, projects, locations):
Selected State:
className="shadow-lg border-2 border-blue-500 bg-gradient-to-br from-white to-gray-50"Default State:
className="hover:shadow-md hover:border-gray-300 bg-white border"Complete Example:
<Card
className={`p-5 cursor-pointer transition-all ${
isSelected
? "shadow-lg border-2 border-blue-500 bg-gradient-to-br from-white to-gray-50"
: "hover:shadow-md hover:border-gray-300 bg-white border"
}`}
onClick={() => handleSelect(item.id)}
>
{/* Card content */}
</Card>Static Cards
For non-interactive content display:
<Card className="p-6 bg-white">
{/* Content */}
</Card>Buttons
Important: All buttons and clickable elements MUST include the cursor-pointer class to ensure proper user feedback.
Primary Button
For main actions:
<Button size="sm" className="cursor-pointer">
<Plus className="w-4 h-4 mr-2" />
Add Item
</Button>Secondary Button
For secondary actions:
<Button variant="outline" size="sm" className="cursor-pointer">
<Settings className="w-4 h-4 mr-2" />
Settings
</Button>Danger Button
For destructive actions:
<Button
variant="ghost"
size="sm"
className="text-red-600 hover:text-red-700 cursor-pointer"
>
<Trash2 className="w-4 h-4" />
</Button>Links and Interactive Elements
All clickable elements (links, buttons, interactive cards, etc.) must include cursor-pointer:
<Link href="/path" className="cursor-pointer">
Click me
</Link>
<div onClick={handleClick} className="cursor-pointer">
Interactive element
</div>List Items
List Item Containers
For lists of items (routes, upstreams, configurations):
Standard List Item:
<div className="p-4 bg-gray-50 border border-gray-300 rounded-lg">
{/* Item content */}
</div>Grid Layout Lists: For displaying multiple items per row:
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-3">
{items.map(item => (
<div className="p-4 bg-gray-50 border border-gray-300 rounded-lg">
{/* Item content */}
</div>
))}
</div>Key specifications:
- Background:
bg-gray-50- Light gray background for subtle contrast - Border:
border border-gray-300- Darker gray border for clear definition - Padding:
p-4- Consistent internal spacing - Border radius:
rounded-lg- Rounded corners for modern look - Grid layout: Responsive columns (1 on mobile, 2 on medium, 3 on large screens)
- Gap:
gap-3- Consistent spacing between grid items
Forms
Input Fields
All inputs should have white backgrounds in light mode:
<Input
type="text"
placeholder="Search..."
className="bg-white"
/>Select Dropdowns
<Select>
<SelectTrigger className="w-[200px] bg-white">
<SelectValue placeholder="Select option" />
</SelectTrigger>
<SelectContent>
<SelectItem value="option1">Option 1</SelectItem>
</SelectContent>
</Select>Tables
Header Style
<thead>
<tr className="border-b border-gray-200 bg-gray-50">
<th className="text-left text-xs font-medium text-gray-600 uppercase tracking-wider py-3 px-6">
Column Name
</th>
</tr>
</thead>Row Style
<tr className="hover:bg-gray-50 transition-colors cursor-pointer">
<td className="py-3 px-6">
<span className="font-mono text-sm text-gray-900">{value}</span>
</td>
</tr>Status Indicators
Status Pills
// Active/Success
<span className="inline-flex items-center px-2 py-0.5 rounded-full text-xs font-medium bg-green-100 text-green-800">
Active
</span>
// Inactive/Neutral
<span className="inline-flex items-center px-2 py-0.5 rounded-full text-xs font-medium bg-gray-100 text-gray-800">
Inactive
</span>
// Error/Warning
<span className="inline-flex items-center px-2 py-0.5 rounded-full text-xs font-medium bg-red-100 text-red-800">
Error
</span>Type Badges
For categorization (e.g., DNS record types):
<span className="inline-flex items-center px-2 py-0.5 rounded text-xs font-medium bg-blue-100 text-blue-800">
A
</span>Icons
Icon Sizing
w-3 h-3- Inline with small textw-4 h-4- Standard button/inline iconsw-5 h-5- Card headers and emphasisw-6 h-6- Feature iconsw-12 h-12- Empty state icons
Icon Colors
text-gray-400- Default/inactivetext-gray-600- Secondarytext-blue-600- Primary/activetext-green-600- Successtext-red-600- Danger/delete
Loading States
Full Page Loader
<div className="flex items-center justify-center min-h-[400px]">
<Loader2 className="w-8 h-8 animate-spin text-gray-400" />
</div>Inline Loader
<Loader2 className="w-4 h-4 animate-spin" />Empty States
<div className="text-center py-12">
<Database className="w-12 h-12 text-gray-300 mx-auto mb-4" />
<h3 className="text-lg font-medium text-gray-900 mb-2">No items found</h3>
<p className="text-gray-500 mb-4">Create your first item to get started</p>
<Button>
<Plus className="w-4 h-4 mr-2" />
Create Item
</Button>
</div>Layout Patterns
Page Headers
<div className="border-b border-gray-200 pb-5">
<div className="flex items-center justify-between">
<div>
<h1 className="text-3xl font-semibold text-gray-900">Page Title</h1>
<p className="text-sm text-gray-500 mt-1">Page description goes here</p>
</div>
<div className="flex items-center gap-3">
{/* Actions */}
</div>
</div>
</div>Section Headers
<div className="flex items-center justify-between mb-4">
<h2 className="text-xl font-semibold text-gray-900">Section Title</h2>
<Button size="sm">Action</Button>
</div>Spacing Guidelines
Padding
p-3- Compact paddingp-4- Small paddingp-5- Medium padding (cards)p-6- Large padding (sections)p-8- Extra large (empty states)
Margins
gap-1- Tight grouping (icon buttons)gap-2- Close related itemsgap-3- Standard spacinggap-4- Section spacinggap-6- Major sections
Common Patterns
space-y-4- Vertical form fieldsspace-y-6- Page sectionsmb-4- After headersmt-1- Descriptions after titles
Animation & Transitions
Standard Transitions
Always include smooth transitions for interactive elements:
className="transition-all" // For multiple properties
className="transition-colors" // For color changes only
className="transition-shadow" // For shadow changes onlyHover States
- Scale: Avoid scaling unless for specific emphasis
- Colors: Subtle color shifts (e.g.,
gray-600togray-700) - Shadows: Add depth on hover with
hover:shadow-md
Accessibility Standards
-
Keyboard Navigation
- All interactive elements must be keyboard accessible
- Include visible focus states
- Logical tab order
-
ARIA Labels
- Use semantic HTML where possible
- Add aria-labels for icon-only buttons
- Include screen reader only text when needed
-
Color Contrast
- Ensure WCAG AA compliance minimum
- Don't rely solely on color for information
-
Click Targets
- Minimum 44x44px click areas
- Adequate spacing between interactive elements
Code Patterns
Conditional Classes
Use template literals for complex conditionals:
className={`
base-classes
${condition ? "true-classes" : "false-classes"}
${anotherCondition && "additional-classes"}
`}Icon + Text Patterns
Always include margin between icon and text:
<Button>
<IconName className="w-4 h-4 mr-2" />
Button Text
</Button>Responsive Design
Mobile-first approach with Tailwind breakpoints:
- Default: Mobile styles
sm:- 640px and upmd:- 768px and uplg:- 1024px and upxl:- 1280px and up
Do's and Don'ts
Do's ✅
- Use consistent spacing throughout
- Provide clear visual feedback for all interactions
- Keep animations subtle and fast
- Use semantic color choices
- Test with keyboard navigation
- Consider loading and error states
Don'ts ❌
- Don't use more than 2-3 font sizes per page
- Don't mix button styles in the same context
- Don't use pure black (#000) for text
- Don't rely only on hover states for important information
- Don't create custom colors outside the palette
- Don't use inline styles
Implementation Notes
- All components should use the shared UI package from
@workspace/ui - Custom components should follow these patterns
- When in doubt, check existing implementations
- Document any deviations from these standards
This is a living document. Update it when new patterns emerge or existing ones need refinement.