---
name: ui-components
description: |
  Generates standardized SmartStack UI components.
  Use this skill when:
  - Creating React page (.tsx) in src/pages/
  - Creating React component in src/components/
  - User asks to create cards, grids, tables, or Kanban
  - Claude detects creation of an entity list with display
  - User mentions "card", "grid", "table", "list", "kanban"
  - User asks for tooltips or infobubbles
  - Creating a page with entity display
  - Managing disabled states with explanatory messages
  - User mentions "dashboard", "chart", "kpi", "analytics", "graph"
  - Creating a dashboard with KPI cards or charts
  Scope: Pages, Components, Cards, Tables, Grids, Kanban boards, Tooltips, Dashboards, Charts
---

# Skill UI Components SmartStack

**Reference:** [_shared.md](../_shared.md) for architecture, i18n

## WHEN THIS SKILL ACTIVATES

| Trigger | Example |
|---------|---------|
| React page/component creation | File in `src/pages/**/*.tsx` or `src/components/**/*.tsx` |
| List creation | "Display products in cards" |
| Keywords | "card", "grid", "table", "kanban", "tooltip" |
| Disabled states | "Disable button with explanatory message" |
| Dashboard/Chart creation | "dashboard", "chart", "kpi", "analytics", "graph", "metrics" |

## Detailed patterns

- For EntityCard (mandatory): [patterns/entity-card.md](patterns/entity-card.md)
- For DataTable: [patterns/data-table.md](patterns/data-table.md)
- For Grid layouts: [patterns/grid-layout.md](patterns/grid-layout.md)
- For Kanban boards: [patterns/kanban.md](patterns/kanban.md)
- For Dashboard & Charts: [patterns/dashboard-chart.md](patterns/dashboard-chart.md)
- For styling rules: [style-guide.md](style-guide.md)
- For accessibility: [accessibility.md](accessibility.md)

## CORE RULES (always apply)

### EntityCard is Mandatory
**ALWAYS use `EntityCard` for entity cards. NEVER use custom cards with divs.**
```typescript
import { EntityCard, ProviderCard, TemplateCard } from '@/components/ui/EntityCard';
```

### CSS Variables (NEVER hardcode colors)
**NEVER use hardcoded Tailwind colors.** ALWAYS use CSS variables for theme compliance.
```tsx
// CORRECT
<span className="bg-[var(--info-bg)] text-[var(--info-text)]">Badge</span>

// WRONG
<span className="bg-blue-500/10 text-blue-500">Badge</span>
```

### Responsive Grid
```tsx
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4 gap-6">
  {items.map(item => <EntityCard key={item.id} {...mapToCardProps(item)} />)}
</div>
```

### Ghost Buttons: NO BORDER
```tsx
// Ghost action (NO BORDER!)
<button className="px-4 py-2 rounded-[var(--radius-button)] text-[var(--text-secondary)] hover:bg-[var(--bg-hover)]">
  Action
</button>
```

### TypeScript Interfaces
**ALWAYS define explicit TypeScript interfaces for component props.** Never use `any`.

### Semantic HTML
**ALWAYS use `<button>` for click actions, `<a>` or `<Link>` for navigation.** Never use `<div role="button">`.

### Performance
- `memo()` for list item components
- `useCallback` for event handlers passed as props
- `useMemo` for expensive computations
- Unique `id` for list keys (NEVER array index)

## ABSOLUTE RULES

| DO | DON'T |
|----|-------|
| CSS variables for ALL colors | Hardcoded Tailwind colors (`bg-blue-500`) |
| `--success-dot`, `--warning-dot`, `--error-dot` for action buttons | `bg-emerald-500`, `bg-amber-500`, `bg-red-500` |
| Ghost buttons WITHOUT border | `border border-[var(--border-color)]` on ghost |
| EntityCard for entities | Custom cards with manual divs |
| Responsive grid 1->2->3->4 | Fixed non-responsive grid |
| h-full + flex-1 + mt-auto | Unaligned buttons in grid |
| Empty, loading, and error states | Native HTML tooltip |
| Explicit TypeScript interfaces | `any` or implicit types |
| `<button>` for click actions | `<div role="button">` |
| `memo()` for list item components | Unmemoized components in loops |
| `useCallback` for event handlers | Inline arrow functions in JSX |
| Unique `id` for list keys | Array index as key |

### Error States with Retry

**ALWAYS provide user-friendly error states with retry capability.**

```tsx
{error && (
  <div className="p-4 bg-[var(--error-bg)] border border-[var(--error-border)] rounded-[var(--radius-card)]">
    <div className="flex items-center">
      <AlertCircle className="h-5 w-5 text-[var(--error-text)]" />
      <span className="ml-2 text-[var(--error-text)]">{error}</span>
    </div>
    <button
      onClick={() => refetch()}
      className="mt-2 text-sm text-[var(--error-text)] hover:opacity-80 underline"
    >
      {t('common:actions.retry')}
    </button>
  </div>
)}
```

**Rules:**
- Use semantic error CSS variables (`--error-bg`, `--error-border`, `--error-text`)
- Always provide retry button for recoverable errors
- Use Lucide `AlertCircle` icon (not inline SVG)
- Keep error messages user-friendly (not technical stack traces)
