Skip to content

Tailwind v4 + shadcn/ui foundation in frontend #94

@Gastonfoncea

Description

@Gastonfoncea

Introduce Tailwind v4 and shadcn/ui into the frontend/ workspace via a coexistence-first strategy. This issue tracks the foundation PR; subsequent component migrations have their own follow-up issue.

What this includes

  • Tailwind v4 install + PostCSS config (@tailwindcss/postcss)
  • @theme block in frontend/app/globals.css mapping brand tokens (accent, bg, surface, text variants, fonts) to CSS variables → utility classes like bg-bg, text-accent, font-display
  • shadcn/ui setup: components.json (new-york style, RSC, aliases match tsconfig), lib/utils.ts with cn() helper, frontend/components/ui/ directory
  • First shadcn primitive: Button
  • Migration of ApiKeysSection and ConnectedAppsSection outer card + header to Tailwind utility classes — first real-world test of the migration pattern

What this does NOT include

  • Modifying the legacy globals.css (3,790 lines of design system used by /app/*, /oauth/*, landing) — coexistence preserved
  • Migration of any other screens or components
  • shadcn primitives other than Button — added on demand when a real consumer needs them

Why this approach

The legacy CSS in globals.css is the app's entire current design system (verified during planning — .dash-*, .btn-*, .profile-card, .modal-*, .field-* are used across all authenticated routes, not just the landing). Wholesale isolation or refactor risks breaking the whole product. Instead, Tailwind coexists with legacy and migration happens gradually one component at a time.

The ! modifier convention (discovered during this PR)

The legacy * { padding: 0; margin: 0 } reset is unlayered, while all Tailwind utilities live in @layer utilities. Per CSS Cascade L5, unlayered author styles beat layered styles regardless of specificity, so utility classes like p-7 lose to the universal reset.

We tried wrapping legacy in @layer legacy to fix this, but Tailwind v4's Preflight (in @layer base) then started winning over legacy element styles (h1, body, ul), breaking layouts across the entire app. We reverted.

The convention now: properties that fight the universal reset (padding, margin) use Tailwind's ! modifier (e.g., p-7!) which generates !important and beats the unlayered legacy reset. The convention is documented in detail in docs/superpowers/specs/2026-05-17-tailwind-adoption-design.md under "Migration convention — the ! modifier".

Spec & plan

  • Spec: docs/superpowers/specs/2026-05-17-tailwind-adoption-design.md
  • Plan: docs/superpowers/plans/2026-05-17-tailwind-adoption-foundation.md

Follow-up

See the separate issue for the broader app-wide migration roadmap.

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

No type
No fields configured for issues without a type.

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions