| name | ui |
| description | Use when building or editing frontend UI components, layouts, styling, design system usage, colors, dark mode, or icons. |
Source Cursor rule: .cursor/rules/ui.mdc.
Original Cursor alwaysApply: true.
UI Components
Design System Priority
- First choice:
@trycompai/design-system
- Fallback:
@trycompai/ui only if DS doesn't have the component
import { Button, Card, Input, Sheet, Badge } from '@trycompai/design-system';
import { Add, Close, ArrowRight } from '@trycompai/design-system/icons';
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.
<Button variant="destructive" size="sm" loading={isLoading}>Delete</Button>
<Button type="submit" iconRight={<ArrowRight size={16} />}>Continue</Button>
<Badge variant="outline">Active</Badge>
<Button className="bg-red-500">Delete</Button>
Layout with Wrapper Divs
For layout concerns, wrap DS components:
<div className="w-full">
<Button>Full Width</Button>
</div>
<Stack gap="4" direction="row">
<Button>First</Button>
<Button>Second</Button>
</Stack>
Componentize Repeated Patterns
If a pattern appears 2+ times, extract it:
<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>
Extension Strategy
When you need new styling:
- Check existing variants - component may already support it
- Add a variant to the component's
cva definition
- Create a new component if it's a genuinely new pattern
const badgeVariants = cva("...", {
variants: {
variant: {
counter: "bg-muted text-muted-foreground tabular-nums font-mono",
},
},
});
Semantic Colors
Use CSS variables, not hardcoded colors:
<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:
<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:
import { Add, Close, ChevronDown } from '@trycompai/design-system/icons';
<Add size={16} />
import { Plus, X } from 'lucide-react';
<Plus className="h-4 w-4" />
Anti-Patterns
<div style={{ display: 'flex' }}>
<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.