# At most one icon library

- **Pattern:** `ab-000224` (`ai-slop-code-drift.ui-stack-drift.dual-icon-library`)
- **Severity:** low
- **Lifecycle:** active
- **Last modified:** 2026-04-18
- **Canonical URL:** https://auditbuffet.com/patterns/ab-000224
- **License:** CC-BY-4.0 — attribute to AuditBuffet Pattern Catalog (https://auditbuffet.com/patterns/ab-000224)

## Why it matters

Two icon libraries ship two SVG sprite sheets, two sets of stroke-width defaults, and two sizing APIs. Users see icons at different visual weights depending on which component rendered them — Lucide's 2px strokes next to React Icons' Font Awesome 1px strokes look mismatched at the same pixel size. Bundle size also grows unnecessarily since tree-shaking rarely eliminates a full icon package, and screen readers receive inconsistent aria-hidden and role attributes.

## Severity rationale

Low because icon drift is cosmetic and bundle-weight, not functional, but it still shows on every page load.

## Remediation

Pick one library (Lucide and Heroicons both work well for modern React apps) and migrate every import. Enumerate usage with `grep -rl "from 'react-icons'" src/`, then replace each icon one-for-one with a `lucide-react` equivalent. Remove the loser: `npm uninstall react-icons`. Document the canonical import path in `src/components/ui/README.md` so new contributors pick the right library on their first PR.

## Detection

- **ID:** `dual-icon-library`
- **Severity:** `low`
- **What to look for:** Apply the three-condition rule against this exact icon library allowlist: `lucide-react`, `react-icons`, `@heroicons/react`, `@radix-ui/react-icons`, `react-feather`, `@phosphor-icons/react`, `@tabler/icons-react`, `iconoir-react`, `@iconify/react`, `react-lottie`. Count all package names and file counts for each library.
- **Pass criteria:** 0 or 1 icon libraries from the allowlist actively used. Report even on pass: "Canonical icon library: [name] ([N] importing files)."
- **Fail criteria:** 2 or more icon libraries from the allowlist meet all three conditions (at least 1 non-escape-hatch importing file).
- **Skip (N/A) when:** 0 icon libraries from the allowlist appear in `RUNTIME_DEPS`.
- **Detail on fail:** `"2 active icon libraries: 'lucide-react' (10 files) AND 'react-icons' (4 files). Pick one for visual consistency and bundle size."`
- **Remediation:** Two icon libraries means inconsistent stroke widths, different sizing systems, double the bundle. Pick one — Lucide and Heroicons are both excellent — and migrate:

  ```bash
  grep -rl "from 'react-icons'" src/
  # Convert each icon import
  npm uninstall react-icons
  ```

---

Taxons: dependency-coherence

HTML version: https://auditbuffet.com/patterns/ab-000224
