Repository navigation
Material UI
Material UI (MUI) is the primary UI component library for the Food Oasis client. We use it for layout, forms, buttons, dialogs, tables, date pickers, and theming.
This page is for new developers: what we use, where it lives in the repo, how to write UI with it, and how to upgrade safely.
| Package | Role |
|---|---|
@mui/material ^7 |
Core components (Button, Grid, TextField, Dialog, …) |
@mui/icons-material ^7 |
Icon components |
@mui/x-data-grid ^7 |
Admin verification / data-entry tables |
@mui/x-date-pickers ^7 |
Time pickers (organization hours) |
@emotion/react / @emotion/styled
|
CSS-in-JS engine MUI depends on |
Defined in client/package.json.
Not used anymore
-
@mui/lab— removed in the v7 migration. Prefer core components (e.g.Buttonwith theloadingprop instead ofLoadingButton). -
@mui/material/Unstable_Grid2— Grid2 was folded intoGridin v7. ImportGridfrom@mui/material.
Related override
-
react-isis pinned to18.3.1via npmoverridesbecause MUI v7 declaresreact-is ^19while the app is still on React 18. Revisit this when upgrading to React 19.
| Path | Purpose |
|---|---|
client/src/theme/ |
Theme: palette, typography, breakpoints, component overrides |
client/src/theme/index.tsx |
ThemeProvider wrapper used by the app |
client/src/App.tsx |
Wraps the app in our ThemeProvider
|
client/src/components/MuiDemo/ |
Internal visual showcase of theme + components |
client/src/components/Admin/ui/ |
Shared admin UI wrappers (Textarea, Label, dialogs, …) |
- From
client/:npm start - Open http://localhost:3000/admin/muidemo
Useful for checking buttons, chips, typography, and palette changes without hunting through the app.
Prefer named imports from the package roots:
import { Box, Button, Grid, TextField, Typography } from "@mui/material";
import CheckIcon from "@mui/icons-material/Check";Icons: import each icon from its own path (@mui/icons-material/Check) rather than barrel-importing the whole package.
Prefer MUI’s sx prop and theme tokens over one-off CSS files:
<Box
sx={(theme) => ({
color: theme.palette.headingText.main,
p: 2,
})}
>
…
</Box>Custom palette keys (e.g. headingText, foodPantry, confirmed) are declared in client/src/theme/palette.tsx with TypeScript module augmentation so they type-check.
Custom button variants such as gray and recenter are also declared there and styled in theme overrides.
In MUI v7, the old item / xs / sm API is gone. Use the size prop:
// ✅ v7
<Grid container spacing={2}>
<Grid size={{ xs: 12, md: 6 }}>…</Grid>
<Grid size={12}>…</Grid>
</Grid>
// ❌ v5 (do not use)
<Grid container>
<Grid item xs={12} md={6}>…</Grid>
</Grid>Gotcha: v5 Grid containers were implicitly width: 100%. v7 containers are only display: flex + minWidth: 0. A nested <Grid container> inside a flex parent can shrink to content width. If a nested row collapses on desktop, add sx={{ width: "100%" }} (or size={12}) to that container.
Do not use Grid as a generic flex wrapper when there is no grid layout. Prefer Box or Stack (see map filter chips in Advanced Filters).
- Formik + Yup drive most forms.
- Pass boolean errors to MUI:
error={touched.field && Boolean(errors.field)}. - Shared multiline field:
Admin/ui/Textarea.tsx(error?: boolean).
- Admin tables:
@mui/x-data-grid(DataGrid,GridColDef,GridRowSelectionModel, …). SeeVerificationAdminGridMui.tsx. - Hours UI:
@mui/x-date-pickerswithLocalizationProvider+ dayjs adapter. SeeOpenTimeForm.tsx.
Prefer slotProps over deprecated componentsProps (still works in v7, but marked deprecated):
<Tooltip slotProps={{ tooltip: { sx: { fontSize: "0.95rem" } } }}>
…
</Tooltip>Typography with variant="body1" defaults to a <p>. Do not put block elements (Alert, Box, Paper) inside it — React will warn about invalid nesting. Use component="div" or wrap the block in a sibling Box.
Responsive row
<Stack direction={{ xs: "column", sm: "row" }} spacing={2} alignItems="center">
…
</Stack>Theme-aware styles
sx={(theme) => ({
borderColor: theme.palette.filterButtons.border.selected,
})}Loading button (no @mui/lab)
<Button variant="contained" loading={isSubmitting} type="submit">
Save
</Button>- Read the migration guide for the target major (e.g. v6, v7).
-
Bump related packages together in
client/package.json:-
@mui/material,@mui/icons-material -
@mui/x-data-grid,@mui/x-date-pickers(X packages often have their own majors) - Keep
@emotion/*compatible
-
-
Run official codemods when available (Grid
sizeprops, etc.), then fix leftovers by hand. -
Reinstall and verify from
client/:
npm install
npm run typecheck
npm run build
npm run format # prettier — avoid noisy follow-up PRs after codemods-
Visual QA
- Food seeker:
/organizations(desktop + mobile list/map) - Admin: organization edit tabs, verification Data Grid, account forms
- Theme demo:
/admin/muidemo
- Food seeker:
-
Watch for regressions
- Nested
Grid containerwidth (see above) - Data Grid selection /
valueGettersignature changes - Date picker
errorprops must be booleans -
react-draggable+ mobile drawer: keepnodeRefon the draggable child; pinreact-draggablecarefully if upgrading
- Nested
Prefer a dedicated upgrade PR (not mixed with feature work). After merge, update this wiki page’s version table if majors change.
- MUI docs — Getting started
- MUI System —
sxprop - Grid
- MUI X Data Grid
- MUI X Date Pickers
- Optional video playlist (intro): Material UI tutorial playlist