veza/apps/web/src/components/COMPONENT_USAGE.md
senke f8655ebaed consistency: remove unused button variants (neon, glass, premium, link)
- Removed neon, glass, premium, and link variants from Button component
- Replaced variant="link" in PostCard with variant="ghost" (with underline)
- Replaced variant="premium" in LibraryPage and FAB with variant="default"
- Updated COMPONENT_USAGE.md to reflect removed variants
- Remaining variants: default, destructive, outline, secondary, ghost
- Action 9.3.1.2 complete
2026-01-16 02:13:51 +01:00

9.5 KiB

Component Usage Guide

Last Updated: 2025-01-27
Purpose: Guide for when and how to use design system components

Table of Contents

  1. Button
  2. Card
  3. Input
  4. Select
  5. Dialog
  6. Alert
  7. Badge
  8. Best Practices

Button

Location: @/components/ui/button
Import: import { Button } from '@/components/ui/button'

When to Use

DO use Button component for:

  • All interactive buttons (primary actions, secondary actions, navigation)
  • Icon buttons
  • Link-style buttons
  • Destructive actions (delete, remove)

DON'T use:

  • Native <button> elements (ESLint will warn)
  • Custom button implementations with inline styles

Variants

Variant Use Case Example
default Primary actions, main CTAs "Save", "Submit", "Upload"
outline Secondary actions, outlined style "Cancel", "Back", inactive states
ghost Tertiary actions, minimal style Icon buttons, menu items, subtle actions
destructive Destructive actions "Delete", "Remove", "Clear"
secondary Secondary actions with background Alternative to outline
link Link-style buttons (removed - use ghost with underline) "View all", "Learn more"

Note: Variants neon, glass, premium, and link have been removed. Use default, outline, or ghost instead.

Sizes

Size Use Case
default Standard buttons (h-10)
sm Compact buttons, inline actions (h-8)
lg Prominent CTAs (h-12)
icon Icon-only buttons (h-10 w-10)

Examples

// Primary action
<Button variant="default" onClick={handleSave}>
  Save Changes
</Button>

// Secondary action
<Button variant="outline" onClick={handleCancel}>
  Cancel
</Button>

// Icon button
<Button variant="ghost" size="icon" onClick={handleEdit}>
  <Edit className="w-4 h-4" />
</Button>

// Destructive action
<Button variant="destructive" onClick={handleDelete}>
  Delete Track
</Button>

// Link-style (use ghost with underline)
<Button variant="ghost" className="text-kodo-cyan hover:underline" onClick={handleViewAll}>
  View all tracks
</Button>

Common Patterns

Button Groups:

<div className="flex gap-2">
  <Button variant="outline">Cancel</Button>
  <Button variant="default">Save</Button>
</div>

Icon with Text:

<Button variant="ghost" size="sm">
  <Heart className="w-4 h-4" />
  <span>Like</span>
</Button>

Card

Location: @/components/ui/card
Import: import { Card, CardHeader, CardTitle, CardDescription, CardContent, CardFooter } from '@/components/ui/card'

When to Use

DO use Card component for:

  • Content containers
  • Dashboard widgets
  • Feature cards
  • Data display sections

DON'T use:

  • Custom card implementations
  • Legacy Card component from @/components/base/Card
  • Invalid variant prop (Card doesn't support variants)

Structure

<Card>
  <CardHeader>
    <CardTitle>Title</CardTitle>
    <CardDescription>Optional description</CardDescription>
  </CardHeader>
  <CardContent>
    {/* Main content */}
  </CardContent>
  <CardFooter>
    {/* Footer actions */}
  </CardFooter>
</Card>

Examples

// Simple card
<Card>
  <CardHeader>
    <CardTitle>Track Statistics</CardTitle>
  </CardHeader>
  <CardContent>
    <p>Total plays: 1,234</p>
  </CardContent>
</Card>

// Card with footer actions
<Card>
  <CardHeader>
    <CardTitle>Settings</CardTitle>
    <CardDescription>Manage your preferences</CardDescription>
  </CardHeader>
  <CardContent>
    {/* Settings form */}
  </CardContent>
  <CardFooter>
    <Button variant="default">Save</Button>
  </CardFooter>
</Card>

Styling

  • Card uses className-based styling (no variants)
  • Use className prop for custom styling
  • Default styles: rounded-2xl, border, background, shadow, hover effects

Input

Location: @/components/ui/input
Import: import { Input } from '@/components/ui/input'

When to Use

DO use Input component for:

  • Text inputs
  • Number inputs
  • Email inputs
  • Password inputs
  • Search inputs

DON'T use:

  • Native <input> elements (for consistency)
  • Custom input implementations (unless specialized like AuthInput, ChatInput)

Examples

// Basic input
<Input
  type="text"
  placeholder="Enter track title"
  value={title}
  onChange={(e) => setTitle(e.target.value)}
/>

// With label
<div className="space-y-2">
  <Label htmlFor="title">Track Title</Label>
  <Input
    id="title"
    type="text"
    placeholder="Enter track title"
    value={title}
    onChange={(e) => setTitle(e.target.value)}
  />
</div>

// Disabled state
<Input
  type="text"
  placeholder="Disabled input"
  disabled
/>

Styling

  • Input uses consistent styling: rounded-lg, border, background, focus states
  • Focus state: border-kodo-cyan
  • Disabled state: opacity-50, cursor-not-allowed

Select

Location: @/components/ui/select
Import: import { Select, SelectTrigger, SelectValue, SelectContent, SelectItem } from '@/components/ui/select'

When to Use

DO use Select component for:

  • Dropdown selections
  • Filter options
  • Sort options
  • Choice selections

DON'T use:

  • Native <select> elements (for consistency)
  • Custom select implementations

Examples

// Basic select
<Select value={value} onValueChange={setValue}>
  <SelectTrigger>
    <SelectValue placeholder="Select an option" />
  </SelectTrigger>
  <SelectContent>
    <SelectItem value="option1">Option 1</SelectItem>
    <SelectItem value="option2">Option 2</SelectItem>
    <SelectItem value="option3">Option 3</SelectItem>
  </SelectContent>
</Select>

Dialog

Location: @/components/ui/dialog
Import: import { Dialog } from '@/components/ui/dialog'

When to Use

DO use Dialog component for:

  • Confirmation dialogs
  • Alert dialogs
  • Information dialogs
  • Modal forms

Variants

Variant Use Case
default Standard dialog
alert Error/warning messages (red icon)
confirm Confirmation dialogs (cyan icon)
info Information dialogs (cyan icon)

Examples

// Confirmation dialog
<Dialog
  open={isOpen}
  onClose={() => setIsOpen(false)}
  title="Delete Track"
  variant="alert"
  onConfirm={handleDelete}
  confirmLabel="Delete"
  cancelLabel="Cancel"
>
  <p>Are you sure you want to delete this track? This action cannot be undone.</p>
</Dialog>

Alert

Location: @/components/ui/alert
Import: import { Alert, AlertDescription } from '@/components/ui/alert'

When to Use

DO use Alert component for:

  • Success messages
  • Warning messages
  • Error messages (non-critical)
  • Information messages

Examples

// Success alert
<Alert variant="success">
  <AlertDescription>Track uploaded successfully!</AlertDescription>
</Alert>

// Error alert
<Alert variant="error">
  <AlertDescription>Failed to upload track. Please try again.</AlertDescription>
</Alert>

Badge

Location: @/components/ui/badge
Import: import { Badge } from '@/components/ui/badge'

When to Use

DO use Badge component for:

  • Status indicators
  • Tags
  • Counts
  • Labels

Examples

// Status badge
<Badge variant="success">Active</Badge>
<Badge variant="error">Inactive</Badge>

// Count badge
<Badge variant="secondary">42</Badge>

Best Practices

1. Always Use Design System Components

  • Use Button instead of <button>
  • Use Input instead of <input>
  • Use Card instead of custom card implementations
  • Use Select instead of native <select>

2. Component Composition

  • Compose components using sub-components (e.g., CardHeader, CardContent)
  • Use className for custom styling when needed
  • Don't override design system styles unnecessarily

3. Accessibility

  • All components include proper ARIA attributes
  • Focus states are handled automatically
  • Keyboard navigation is supported

4. Consistency

  • Use consistent variants across similar actions
  • Follow the variant guidelines (default for primary, outline for secondary, ghost for tertiary)
  • Use appropriate sizes (sm for compact, default for standard, lg for prominent)

5. Performance

  • Components are optimized with React.forwardRef
  • Use asChild prop when composing with other components (Button only)

6. Testing

  • All components have test files
  • Test components before using in production
  • Follow existing test patterns

Migration Guide

Migrating from Custom Buttons

Before:

<button className="px-4 py-2 bg-kodo-cyan text-white rounded">
  Click me
</button>

After:

<Button variant="default">Click me</Button>

Migrating from Custom Cards

Before:

<div className="rounded-lg border bg-kodo-ink p-4">
  <h3>Title</h3>
  <p>Content</p>
</div>

After:

<Card>
  <CardHeader>
    <CardTitle>Title</CardTitle>
  </CardHeader>
  <CardContent>
    <p>Content</p>
  </CardContent>
</Card>

Resources

  • Design System Colors: See apps/web/src/styles/COLOR_USAGE.md
  • Component Tests: See apps/web/src/components/ui/*.test.tsx
  • Component Source: See apps/web/src/components/ui/*.tsx

Questions?

If you're unsure which component to use:

  1. Check this guide first
  2. Look at similar components in the codebase
  3. Review component test files for usage examples
  4. When in doubt, use the most common variant (default for Button, standard for others)