Skip to main content

ADR-006: Consolidate the Website on Radix + Tailwind

FieldValue
StatusAccepted
DateSeptember 24, 2026
DecidersWes Huber
RelatedWeb app deployment · TrickBookWebsite branch chore/remove-bootstrap

Context​

As of 2026-09-24 the website stacked three UI kits at once:

  • MUI: @mui/material components and @mui/icons-material icons, with a MuiThemeProvider in _app.js.
  • Bootstrap: bootstrap/dist/css/bootstrap.css imported globally in _app.js, plus react-bootstrap Navbar, Nav and NavDropdown in Header.js and LanguageSelector.js, and bootstrap grid and card classes in about a dozen admin and blog pages.
  • Radix + Tailwind: shadcn-style primitives in components/ui/* (button, card, dialog, select, tabs, toast and others), lucide-react icons, and Tailwind utilities across most newer pages.

Three kits meant two CSS resets loaded on every page (bootstrap reboot and Tailwind preflight), three button styles, three dropdown implementations, and a bundle that shipped all of them to every visitor. New work had no default, so each page picked whatever its author knew.

Decision​

  1. Bootstrap is removed. The global stylesheet import, react-bootstrap and bootstrap are dropped. Header.js and LanguageSelector.js move to the Radix DropdownMenu plus Tailwind, and bootstrap grid and card classes are rewritten as Tailwind utilities or existing components/ui primitives. Done on branch chore/remove-bootstrap in TrickBookWebsite.
  2. Radix + Tailwind is the target kit. All new UI uses components/ui/*, Tailwind utilities and lucide-react. No new MUI import is added anywhere.
  3. MUI stays only where it already is. Existing MUI files keep working until each is migrated. Migration is file by file: icons first (swap @mui/icons-material for lucide-react), then components (Typography, Button, Chip, CircularProgress, Box, TextField, Alert, the table set), then the theme provider in _app.js last.

MUI inventory at the decision date​

27 files under pages/ and components/ import from @mui/.

GroupCountFiles
Icons only (@mui/icons-material)1pages/signup.js
Components and icons11Header.js, TrickProgressionSection.js, pages/admin/blog.js, categories.js, create-blog-post.js, create-trick.js, pending-spots.js, spots.js, trickipedia.js, pages/trickipedia/[category].js, pages/trickipedia/[category]/[trick].js
Components only (@mui/material)15AdminLayout.js, AdminNav.js, BlogCard.js, CustomArrow.js, PageHeader.js, TrickCard.js, pages/_app.js (theme provider), about.js, admin/create-spot.js, admin/index.js, admin/spot-enrichment.js, blog.js, blog/[slug].js, questions-support.js, tricklist.js

Most-used MUI components by import count: Typography (10), Button (6), CircularProgress, Chip, Box (4 each), TextField (3). Each already has a components/ui or plain-Tailwind equivalent.

Consequences​

  • Two kits remain until the MUI list above reaches zero; the count is the migration metric.
  • Tailwind preflight is now the only CSS reset. Bootstrap's reboot rules (its body font stack, heading margins, img display, form control defaults) are gone, so any page that leaned on them without saying so needs an explicit Tailwind class.
  • The header and language dropdowns are keyboard and screen-reader accessible through Radix rather than bootstrap's JavaScript.
  • The .navbar-*, .dropdown-* and .profile-dropdown overrides in styles/global.css are replaced by classes that target the Radix markup.
  • Bundle size drops by the bootstrap CSS and react-bootstrap runtime on every page.

Rejected alternatives​

Standardize on MUI: rejected because the newer half of the site (spots, media, riders, shops, events) is already Radix + Tailwind and MUI's emotion runtime is the heaviest of the three.

Keep bootstrap for the grid only: rejected because Tailwind's grid and flex utilities already cover every bootstrap grid usage found (row, col-*, container-fluid, g-4), and a partial bootstrap still ships its full reset.

Big-bang rewrite of all three: rejected because there is no visual regression suite yet; file-by-file keeps each change reviewable.

Rollout​

  1. Remove bootstrap (this ADR's date).
  2. Add a lint rule or CI grep that fails on new @mui/ imports outside the inventory list.
  3. Migrate icons-only and icons-and-components files to lucide-react icons.
  4. Migrate component files, admin pages last since they are internal.
  5. Remove MuiThemeProvider, @mui/material, @mui/icons-material, @emotion/* and material-icons from package.json.