← Dev log

frontend

shadcn/ui: owning the component source

shadcn/ui: owning the component source

The platform started on NextUI, a traditional installed component library, and migrated to shadcn/ui mid-project. The why matters more than either library alone.

Most component libraries — NextUI, MUI, Chakra — install as a dependency: you import prebuilt, compiled components, and customising means fighting the library's own theming API. shadcn/ui is a CLI that generates the actual component source directly into your repo — Radix primitives underneath for accessibility behaviour, Tailwind utilities on top, and you own the files.

npx shadcn add button
# writes an actual Button.tsx into your components folder — yours to edit freely

This won for a few concrete reasons:

  • No theming API to fight. Restyling for dark mode, RTL for Arabic, or a full visual refresh is a normal code edit, not learning a black-box theming system.
  • No opaque bundle bloat — only components actually used exist in the codebase at all.
  • It fits a monorepo of apps sharing a UI layer, since the components are just code that composes into a shared package all the apps import from.

The migration commit bundled fixing several real bugs alongside the visual refresh — an auth state race, a Google OAuth Docker config, avatar rendering. Not a coincidence: a large-scale rewrite is often the moment several unrelated small bugs finally get noticed and fixed together, because touching every screen forces a fresh look at things that had been quietly broken. That same migration also took the frontend Docker setup from nine Dockerfiles to two and simplified the TypeScript config.

Tailwind underneath is utility-first — styling composed directly in JSX class names. One shared colour and theme config across every app (React Native's own equivalent via NativeWind) is what keeps the visual language consistent across genuinely separate apps without hand-syncing a design system across each one.