# At most one component library family

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

## Why it matters

Running MUI alongside Chakra ships two theme providers, two sets of primitives, two typography scales, and often two CSS-in-JS runtimes to every page. Bundle size roughly doubles for the styled-component portion of your app, Core Web Vitals degrade on mobile, and designers cannot produce a coherent visual system because every component comes from a different opinionated foundation. Dark mode toggles typically work in one library and break in the other.

## Severity rationale

Medium because the impact is bundle bloat and visual drift rather than correctness or data loss, though both affect production quality.

## Remediation

Audit usage with `grep -rl "from '@mui/material'" src/ | wc -l` and the equivalent for the other library, then port the smaller side. Remove the loser's peer dependencies in one step: `npm uninstall @chakra-ui/react @emotion/react @emotion/styled`. Delete the provider wrapper from `src/app/layout.tsx` or `src/providers/index.tsx` and verify theme tokens now flow from a single source. Run a production build and confirm the removed library is no longer in the bundle analyzer output.

## Detection

- **ID:** `dual-component-library`
- **Severity:** `medium`
- **What to look for:** Apply the three-condition rule against this exact component library allowlist: `@mui/material`, `@chakra-ui/react`, `@chakra-ui/core`, `@mantine/core`, `antd`, `react-bootstrap`, `@blueprintjs/core`, `grommet`, `evergreen-ui`, `@nextui-org/react`, `@nextui-org/system`. EXCLUDE shadcn-ui (it is headless + Radix primitives, not a competing component library — its presence is signaled by `components.json` in the project root and individual Radix imports). EXCLUDE Radix UI primitives (`@radix-ui/*`) — they coexist with shadcn-ui by design. Count all package names found.
- **Detector snippet (shell-capable tools only):** If the tool has shell access, list every source file importing one of the allowlisted component library families. Group by library. If `rg` is not installed or exits >=2, fall back to prose reasoning above.

  ```detect-rg
  rg -l -e "from ['\"]@mui/" -e "from ['\"]@chakra" -e "from ['\"]@mantine/" -e "from ['\"]antd" -e "from ['\"]@ant-design/" src/
  ```

- **Pass criteria:** 0 or 1 styled component libraries from the allowlist actively used. Report even on pass: "Canonical component library: [name] ([N] importing files) — or shadcn-ui (Radix-based, headless)."
- **Fail criteria:** 2 or more styled component libraries from the allowlist meet all three conditions (at least 1 non-escape-hatch importing file).
- **Skip (N/A) when:** 0 styled component libraries from the allowlist appear in `RUNTIME_DEPS`.
- **Detail on fail:** `"2 active component libraries: '@mui/material' (15 files) AND '@chakra-ui/react' (9 files). Mixing component libraries creates inconsistent visual language and bundle bloat."`
- **Remediation:** Two component libraries means double the bundle, double the theme system, double the design language, and zero visual consistency. Pick one and migrate:

  ```bash
  # Inventory the smaller side
  grep -rl "from '@mui/material'" src/ | wc -l
  grep -rl "from '@chakra-ui/react'" src/ | wc -l

  # Migrate the smaller side to the larger one, then:
  npm uninstall @chakra-ui/react @emotion/react @emotion/styled
  ```

Taxons: dependency-coherence

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