ADR-006: Consolidate the Website on Radix + Tailwind
| Field | Value |
|---|---|
| Status | Accepted |
| Date | September 24, 2026 |
| Deciders | Wes Huber |
| Related | Web app deployment · TrickBookWebsite branch chore/remove-bootstrap |
Context
As of 2026-09-24 the website stacked three UI kits at once:
- MUI:
@mui/materialcomponents and@mui/icons-materialicons, with aMuiThemeProviderin_app.js. - Bootstrap:
bootstrap/dist/css/bootstrap.cssimported globally in_app.js, plusreact-bootstrapNavbar,NavandNavDropdowninHeader.jsandLanguageSelector.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-reacticons, 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
- Bootstrap is removed. The global stylesheet import,
react-bootstrapandbootstrapare dropped.Header.jsandLanguageSelector.jsmove to the RadixDropdownMenuplus Tailwind, and bootstrap grid and card classes are rewritten as Tailwind utilities or existingcomponents/uiprimitives. Done on branchchore/remove-bootstrapin TrickBookWebsite. - Radix + Tailwind is the target kit. All new UI uses
components/ui/*, Tailwind utilities andlucide-react. No new MUI import is added anywhere. - 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-materialforlucide-react), then components (Typography,Button,Chip,CircularProgress,Box,TextField,Alert, the table set), then the theme provider in_app.jslast.
MUI inventory at the decision date
27 files under pages/ and components/ import from @mui/.
| Group | Count | Files |
|---|---|---|
Icons only (@mui/icons-material) | 1 | pages/signup.js |
| Components and icons | 11 | Header.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) | 15 | AdminLayout.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,
imgdisplay, 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-dropdownoverrides instyles/global.cssare replaced by classes that target the Radix markup. - Bundle size drops by the bootstrap CSS and
react-bootstrapruntime 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
- Remove bootstrap (this ADR's date).
- Add a lint rule or CI grep that fails on new
@mui/imports outside the inventory list. - Migrate icons-only and icons-and-components files to
lucide-reacticons. - Migrate component files, admin pages last since they are internal.
- Remove
MuiThemeProvider,@mui/material,@mui/icons-material,@emotion/*andmaterial-iconsfrompackage.json.