# UI

> Use when building or editing frontend UI components, layouts, styling, design system usage, colors, dark mode, or icons.

- Skill: `trycompai/ui-2` (Agent Skill)
- Install (CLI): `npx skillmds@latest add trycompai/ui-2`
- Raw SKILL.md: https://api.skillmd.com/api/skills/trycompai/ui-2/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Design & Media
- Author: trycompai (https://skillmd.com/u/trycompai)
- Updated: 2026-09-17
- Page: https://skillmd.com/skills/trycompai/ui-2

---


Source Cursor rule: `.cursor/rules/ui.mdc`.
Original Cursor alwaysApply: `true`.

# UI Components

## Design System Priority

1. **First choice:** `@trycompai/design-system`
2. **Fallback:** `@trycompai/ui` only if DS doesn't have the component

```tsx
// ✅ Design system
import { Button, Card, Input, Sheet, Badge } from '@trycompai/design-system';
import { Add, Close, ArrowRight } from '@trycompai/design-system/icons';

// ❌ Don't use when DS has it
import { Button } from '@trycompai/ui/button';
import { Plus } from 'lucide-react';
```

## No className on DS Components

DS components don't accept `className`. Use variants and props only.

```tsx
// ✅ Use variants
<Button variant="destructive" size="sm" loading={isLoading}>Delete</Button>
<Button type="submit" iconRight={<ArrowRight size={16} />}>Continue</Button>
<Badge variant="outline">Active</Badge>

// ❌ TypeScript will error
<Button className="bg-red-500">Delete</Button>
```

## Layout with Wrapper Divs

For layout concerns, wrap DS components:

```tsx
// ✅ Wrapper for width
<div className="w-full">
  <Button>Full Width</Button>
</div>

// ✅ Use Stack for spacing
<Stack gap="4" direction="row">
  <Button>First</Button>
  <Button>Second</Button>
</Stack>
```

## Componentize Repeated Patterns

If a pattern appears 2+ times, extract it:

```tsx
// Repeated? Make a component
<div className="flex items-center gap-2">
  <div className="w-2 h-2 rounded-full bg-green-500" />
  <span className="text-sm">Active</span>
</div>
// → Create <StatusDot status="active" />
```

## Extension Strategy

When you need new styling:

1. **Check existing variants** - component may already support it
2. **Add a variant** to the component's `cva` definition
3. **Create a new component** if it's a genuinely new pattern

```tsx
// Adding a variant
const badgeVariants = cva("...", {
  variants: {
    variant: {
      // existing...
      counter: "bg-muted text-muted-foreground tabular-nums font-mono",
    },
  },
});
```

## Semantic Colors

Use CSS variables, not hardcoded colors:

```tsx
// ✅ Semantic tokens
<div className="bg-background text-foreground border-border">
<div className="bg-muted text-muted-foreground">
<div className="bg-destructive/10 text-destructive">

// ❌ Hardcoded
<div className="bg-white text-black">
<div className="bg-[#059669]">
```

## Dark Mode

Always support both modes:

```tsx
// Status colors with dark variants
<div className="bg-green-50 dark:bg-green-950/20 text-green-600 dark:text-green-400">
<div className="bg-red-50 dark:bg-red-950/20 text-red-600 dark:text-red-400">
```

## Icons

Carbon icons from DS, not lucide:

```tsx
// ✅ Design system icons with size prop
import { Add, Close, ChevronDown } from '@trycompai/design-system/icons';
<Add size={16} />

// ❌ Don't use lucide
import { Plus, X } from 'lucide-react';
<Plus className="h-4 w-4" />
```

## Anti-Patterns

```tsx
// ❌ Never do these
<div style={{ display: 'flex' }}>              // Inline styles
<Button className="bg-red-500">               // className on DS
<div className="bg-[#059669]">                // Hardcoded colors
<div className="w-[847px]">                   // Arbitrary values
```

## Responsive (MANDATORY — read the `responsive-ui` skill)

Every UI change must work on mobile (375px), tablet (768px), desktop (1280px), and
large desktop (1920px) **by default — nobody has to ask**. Tailwind is mobile-first:
write the base (mobile) layout, widen with `sm:`/`md:`/`lg:`/`xl:`. No fixed widths
without a responsive strategy (`hidden sm:block`, `w-full md:max-w-xs`, or a wrapping
parent). All the rules above still apply: breakpoint classes go on wrapper divs, never
on DS components, and arbitrary pixel values remain an anti-pattern. Wide tables scroll
inside the DS `Table` (`overflow-x-auto`), never the page. Full rules + repo patterns +
checklist: `.claude/skills/responsive-ui/SKILL.md`.

