Files
initiative/specs/010-ui-baseline/research.md

4.2 KiB

Research: UI Baseline

Feature: 010-ui-baseline | Date: 2026-03-05

R1: Tailwind CSS Version Choice

Decision: Use Tailwind CSS v4 (latest stable) Rationale: Tailwind v4 uses a CSS-first configuration approach with @import "tailwindcss" and CSS-based theme customization via @theme. This simplifies setup — no tailwind.config.ts is strictly required for basic usage. Vite has first-class support via @tailwindcss/vite plugin. Alternatives considered:

  • Tailwind v3: Mature but requires JS config file and PostCSS plugin. v4 is stable and recommended for new projects.

R2: shadcn/ui Integration Approach

Decision: Use shadcn/ui CLI to scaffold components into apps/web/src/components/ui/ Rationale: shadcn/ui is not a package dependency — it copies component source code into the project. This gives full control over styling and avoids version lock-in. Components use Tailwind classes + Radix UI primitives. Alternatives considered:

  • Radix UI directly: More low-level, requires writing all styles manually. shadcn/ui provides pre-styled Tailwind components.
  • Material UI / Chakra UI: Heavier runtime, opinionated styling that conflicts with Tailwind approach.

R3: Tailwind v4 + Vite Setup

Decision: Use @tailwindcss/vite plugin instead of PostCSS Rationale: Tailwind v4 provides a dedicated Vite plugin that is faster than the PostCSS approach. Setup is:

  1. Install tailwindcss @tailwindcss/vite
  2. Add plugin to vite.config.ts
  3. Create index.css with @import "tailwindcss"
  4. Import index.css in main.tsx Alternatives considered:
  • PostCSS plugin: Works but slower; Vite plugin is recommended for Vite projects.

R4: Icon Library

Decision: Use Lucide React for icons (remove button, etc.) Rationale: Lucide is the default icon set for shadcn/ui. Tree-shakeable, consistent style, and already expected by shadcn/ui component templates. Alternatives considered:

  • Heroicons: Good quality but not the shadcn/ui default.
  • Inline SVG: Too manual for maintenance.

R5: CSS Utility Helper (cn function)

Decision: Use clsx + tailwind-merge via a cn() utility function Rationale: Standard shadcn/ui pattern. clsx handles conditional classes, tailwind-merge deduplicates conflicting Tailwind classes. The cn() helper is placed in lib/utils.ts. Alternatives considered:

  • clsx alone: Doesn't deduplicate conflicting Tailwind classes (e.g., p-2 p-4).

R6: Component Decomposition

Decision: Extract App.tsx into focused components while keeping them in a single file or minimal files Rationale: The current App.tsx (~280 lines) has inline components (EditableName, MaxHpInput, CurrentHpInput). For the UI baseline, we'll restructure into:

  • App.tsx — layout shell (header, combatant list, action bar)
  • components/combatant-row.tsx — single combatant row with all controls
  • components/ui/ — shadcn/ui primitives (Button, Input, Card)

This keeps the change focused while establishing a scalable component structure. Alternatives considered:

  • Keep everything in App.tsx: Gets unwieldy with Tailwind classes added.
  • Full atomic decomposition: Over-engineered for current scope.

R7: verbatimModuleSyntax Compatibility

Decision: shadcn/ui components work with verbatimModuleSyntax since they use standard ESM imports Rationale: shadcn/ui generates standard TypeScript files with explicit type imports. The cn utility and Radix imports use value imports. No special handling needed.

R8: Biome 2.0 Compatibility

Decision: No conflicts expected; Tailwind class strings are just strings Rationale: Biome formats/lints TypeScript and JSX. Tailwind classes in className props are plain strings, which Biome ignores content-wise. The shadcn/ui generated code follows standard formatting conventions. May need to run pnpm format after generating components.

R9: Knip Compatibility

Decision: May need to configure Knip to recognize shadcn/ui component exports Rationale: shadcn/ui components are copied into the project. If not all are immediately used, Knip may flag them as unused. Solution: only install the shadcn/ui components we actually need (Button, Input, Card/container).