Skip to content

UI Components (shadcn)

Purpose

Katalyst’s shared UI primitives live in src/shared/ui/primitives/ and follow a shadcn-style approach:

  • Source-controlled components (not a black-box library)
  • Tailwind-based styling with consistent tokens
  • Built on proven foundations (Radix UI, cmdk, etc.)

These primitives are the building blocks for higher-level shared components like ConfirmDialog and CommandPalette.

When to use

Use shadcn primitives when:

  • You need a consistent baseline UI (buttons, dialogs, inputs, menus)
  • You want accessible behavior without re-implementing it
  • You need to customize styling locally while keeping a shared foundation

Example

tsx
import { Button } from '@/shared/ui/primitives/button'
import { Dialog, DialogContent, DialogTrigger } from '@/shared/ui/primitives/dialog'

export function ExampleDialog() {
  return (
    <Dialog>
      <DialogTrigger asChild>
        <Button type="button">Open</Button>
      </DialogTrigger>
      <DialogContent>
        <p>Dialog content</p>
      </DialogContent>
    </Dialog>
  )
}

Props (concise)

This section is intentionally high-level:

  • Most primitives accept the underlying Radix/cmdk component props (plus className).
  • Many primitives expose “variants” using class-variance-authority (e.g., buttonVariants).
  • Styling composition uses cn(...) from src/lib/utils.ts (Tailwind merge + conditional classes).

Notes / Gotchas

  • Don’t treat them as vendor code: these primitives are part of your codebase; prefer consistent local improvements over duplicating “one-off” UI.
  • Use cn(...) for class composition: it avoids Tailwind class conflicts and keeps variants predictable.
  • Prefer variants over ad hoc styling: when a style needs to be reused, add a variant (or a wrapper component) rather than sprinkling custom class strings.
  • Extend safely:
    • Add new primitives in src/shared/ui/primitives/ following existing patterns (data-slot attributes, cn, Radix wrappers).
    • Build feature-specific UI as wrappers/components on top of primitives, instead of forking primitives in feature folders.
  • Keep UI separate from logic: primitives/components should stay thin; domain behavior should live in hooks/services.