Skip to content

Migrate off the legacy MUI Grid API (prerequisite for #2770) - #3867

Merged
ChristopherChudzicki merged 2 commits into
mainfrom
chudzick/mui-grid-v2-migration
Sep 4, 2026
Merged

ChristopherChudzicki merged 2 commits into
mainfrom
chudzick/mui-grid-v2-migration

Conversation

@ChristopherChudzicki

@ChristopherChudzicki ChristopherChudzicki commented Aug 31, 2026 •

Copy link
Copy Markdown
Contributor

What are the relevant tickets?

N/A. Prerequisite for #2770 (Renovate's Update material-ui monorepo (major)).

Description (What does it do?)

  • Moves the last @mui/material/Grid usages to the v2 Grid API, so Update material-ui monorepo (major) #2770 can be a rename instead of an API migration bundled into a version bump.
  • Deletes GridLayout's GridContainer/GridColumn — already @deprecated in-repo, and both wrapped the legacy API. Their two consumers now use Grid directly.
  • Drops the legacy Grid/GridProps re-exports from the ol-components barrel, so the old API can't come back by accident.
  • Second commit removes the no-op wrapper the first leaves behind, split so the API migration is reviewable alone.
  • No visual change: the bounding-box diff against main is clean on every surface except one invisible 16px shift on /learningpaths, which is staff-only. See Automated Checks.
Implementation details

Why v7 forces it. Checked against the published tarballs, since the v6 JSDoc is wrong about v7 — it annotates props "will be removed in v7" that survive to 9.4.0.

  • 7.3.11 has no Grid2 directory, its Grid takes size, and the old API is renamed GridLegacy. So on v7 the Grid2 path vanishes and Grid silently becomes the v2 API.
  • 9.4.0 drops GridLegacy entirely.
  • An unmigrated Grid therefore doesn't fail to compile on v7 — it changes layout. That's what makes Grid the one hard gate in the bump.
  • Not just future hygiene: @mitodl/smoot-design 6.33.4 declares @mui/material: ^7.0.0 as a peer while this repo hoists one copy at 6.4.5.

The difference that mattered. A legacy container carries width: 100%; a v2 container does not. So a container that is also a flex item (legacy <Grid item container>) drops to content width on conversion. The four rows that hit this all use justifyContent="space-between", which is meaningless at content width, so they get an explicit size={12}. Containers whose parent isn't itself a container need nothing — display: flex already makes them fill the parent. (Spacing also moves from negative-margin + padding to gap.)

Scope. Seven files. Grep by tag name over-reports here: DepartmentListingPage, TopicsListingPage, SearchDisplay and NewsEventsSection already import Grid2 as Grid, and RelatedPlaylist.tsx has a local styled.div named Grid that isn't MUI at all. ChoiceBoxField forwards caller-supplied grid props, so four call sites also moved from { xs: 3 } to { size: 3 } — only tsc caught those, the test suite passed without them.

Commit 2, and the one real side effect. GridContainer/GridColumn always rendered a container holding one full-width column, which in v2 is two divs and no layout (a gap never renders with one item per row). But <Grid size={12}> was a flex item, which contained ListHeaderGrid's margin: 1rem 0; attached straight to Container (horizontal padding, no padding-top) that top margin now collapses through. On /learningpaths, Container starts 16px lower and ends 16px shorter — same bottom edge, and the header row's own box is identical, so nothing visible moves. Shipping as-is: any fix just relocates the invisible 16px to a different box. Worth knowing it's there if that edge ever gets a background or a border.

Screenshots (if appropriate):

Thumbnails are scaled down — click through for full size. These are for eyeballing; the no-movement claim rests on Automated Checks below.

Public UI — any signed-in learner (`Permission.Authenticated`)

/onboarding

Viewport Before After
desktop onboarding desktop before onboarding desktop after
tablet onboarding tablet before onboarding tablet after
mobile onboarding mobile before onboarding mobile after

/dashboard/profile

Viewport Before After
desktop profile desktop before profile desktop after
tablet profile tablet before profile tablet after
mobile profile mobile before profile mobile after

/dashboard/my-lists/[id]

Viewport Before After
desktop userlist-detail desktop before userlist-detail desktop after
tablet userlist-detail tablet before userlist-detail tablet after
mobile userlist-detail mobile before userlist-detail mobile after
Staff UI — learning-path editors only (`Permission.LearningPathEditor`)

/learningpaths

Viewport Before After
desktop learningpaths-listing desktop before learningpaths-listing desktop after
tablet learningpaths-listing tablet before learningpaths-listing tablet after
mobile learningpaths-listing mobile before learningpaths-listing mobile after

/learningpaths/[id]

Viewport Before After
desktop learningpath-detail desktop before learningpath-detail desktop after
tablet learningpath-detail tablet before learningpath-detail tablet after
mobile learningpath-detail mobile before learningpath-detail mobile after

Automated Checks

Screenshot Comparison. The before/after sets above cover 5 surfaces at 3 viewports. The residual pixel differences are measurement noise rather than layout — re-shooting the same commit reproduces them at the same magnitude, in the same pixels.

Bounding Box Comparison. Dumped getBoundingClientRect() for every rendered element on both branches: nothing moves anywhere except /learningpaths, where Container starts 16px lower and ends 16px shorter, same bottom edge. Nothing renders differently and the route is staff-only, so that is acceptable.

The measurements

Same-commit screenshot controls, worst pair of 4 repeats: 78px at Δ3/255 on /learningpaths/[id] at 2560x1440, and 36px at Δ1 on /learningpaths mobile — against before/after figures of 200px and 31px, overlapping 85-100% of the same pixel coordinates. Every differing pixel sits on the antialiased border-radius corner of a card thumbnail. Hardening the capture (--reduced-motion, software rasterization, animations disabled, awaiting document.fonts.ready and img.decode()) closed it at mobile widths but not at 2560x1440.

The bounding-box dump is exact by comparison: 3 repeat dumps at one commit gave 0 differing rows of 318 and 568 elements. Boxes are diffed as a multiset rather than keyed by DOM path, because removing a wrapper reparents every descendant and would otherwise swamp the diff. It proves nothing moved — it would not catch a color or z-order change, which is what the screenshots are for.

Surface Boxes only on main Boxes only on branch Same box, different CSS
/learningpaths 3 1 1
/learningpaths/[id] 2 0 4
/dashboard/my-lists/[id] 2 0 4
/onboarding 11 11 0
/dashboard/profile 11 11 0

Identical at all three viewports. The two list-detail pages lose exactly the margin-left: -48px / padding-left: 48px wrapper pair, which cancels — content sat at x854 before and after, and nothing new appears. /onboarding and /dashboard/profile swap the ChoiceBoxField grid from negative-margin spacing to gap, so every box moves +12,+12 and shrinks 12x12; the item's content box on main (656+12, 272+12, 309-12, 71-12) is exactly the branch's border box, which is why those two surfaces are byte-identical in the screenshots. The "different CSS" rows are gap: normal -> gap: 0px, equivalent on a flex container, rects identical to the hundredth of a pixel.

How can this be tested?

  1. Ensure yarn install has run
  2. View main vs this branch at each of these paths, at desktop and mobile widths.
    • Public Paths: /dashboard/my-lists/[id], /onboarding, /dashboard/profile
    • Adin Paths: /learningpaths, /learningpaths/[id]

The two list pages are where size={12} restores a container width, so a regression would look like a header row hugging its content instead of spanning.

ChristopherChudzicki and others added 2 commits August 31, 2026 12:16
Move every remaining `@mui/material/Grid` usage to the v2 Grid API
(`@mui/material/Grid2`), which is a prerequisite for the @mui/material v7
bump: v7 removes the `Grid2` import path and repoints `Grid` at the v2 API,
renaming the old one to `GridLegacy`. Doing the API move on v6 first keeps
the version bump a mechanical rename.

The two APIs lay out differently, so this is not purely cosmetic:

- Legacy Grid spaces items with a negative container margin plus per-item
  padding; the v2 Grid uses `gap` and subtracts the gap from item widths.
- A legacy `container` carried `width: 100%`. A v2 container does not, so a
  container that is also a flex item (legacy `<Grid item container>`) needs
  an explicit `size` to stay full-width. The three converted rows in
  ItemsListingComponent and the one in LearningPathListingPage get
  `size={12}` for this reason; containers whose parent is not itself a
  container need nothing, since a block-level flex box already fills its
  parent.

Also drop GridLayout's `GridContainer`/`GridColumn`. Both were already
marked `@deprecated` in-repo as predating the site's formal designs, and
both wrapped the legacy API; their two consumers now use Grid directly with
the column widths inlined. The legacy `Grid` re-export is removed from the
ol-components barrel so the old API cannot come back by accident.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
`GridContainer`/`GridColumn` always rendered a container holding a single
full-width column, so the pair contributed two divs and no layout: a v2
container spaces items with `gap`, and a gap never renders when there is one
item per row. Inlining them in the previous commit preserved that shape to
keep the API migration reviewable on its own; this removes it.

The wrapper was not quite free. `<Grid size={12}>` is a flex item, which
establishes an independent formatting context, so `ListHeaderGrid`'s vertical
margins could not collapse out of it — removing the wrapper puts them in
`Container`'s block formatting context, where they can. Verified they don't:
against the pre-migration render, `/learningpaths` differs only inside a
2x40px region near the page bottom, with the heading and every element above
it byte-identical. Collapsing a 1rem margin would have shifted the page.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@github-actions

Copy link
Copy Markdown

OpenAPI Changes

No changes detected

View full changelog

Unexpected changes? Ensure your branch is up-to-date with main (consider rebasing).

@ChristopherChudzicki ChristopherChudzicki added the Needs Review An open Pull Request that is ready for review label Aug 31, 2026
@ChristopherChudzicki
ChristopherChudzicki marked this pull request as ready for review August 31, 2026 19:16
@ChristopherChudzicki
ChristopherChudzicki requested a review from a team as a code owner August 31, 2026 19:16
Copilot AI balanced review requested due to automatic review settings August 31, 2026 19:16

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Migrates remaining legacy MUI Grid usage to Grid v2, preparing for the Material UI major upgrade in #2770.

Changes:

  • Converts legacy Grid props and imports to Grid2.
  • Updates ChoiceBox grid-prop consumers.
  • Removes deprecated layout wrappers and legacy barrel exports.

Reviewed changes

Copilot reviewed 12 out of 12 changed files in this pull request and generated no comments.

Show a summary per file
File Description
frontends/ol-components/src/index.ts Removes legacy Grid exports.
frontends/ol-components/src/components/SelectField/SelectField.stories.tsx Migrates story layout to Grid2.
frontends/ol-components/src/components/Logo/Logo.stories.tsx Migrates logo story to Grid2.
frontends/ol-components/src/components/ChoiceBox/ChoiceBoxFieldRadio.stories.tsx Updates radio story sizing.
frontends/ol-components/src/components/ChoiceBox/ChoiceBoxFieldCheckbox.stories.tsx Updates checkbox story sizing.
frontends/ol-components/src/components/ChoiceBox/ChoiceBoxField.tsx Migrates ChoiceBox field layout to Grid2.
frontends/ol-components/src/components/ChoiceBox/ChoiceBox.tsx Updates public grid-prop types.
frontends/main/src/page-components/ItemsListing/ItemsListingComponent.tsx Replaces deprecated wrappers with Grid2.
frontends/main/src/components/GridLayout/GridLayout.tsx Deletes deprecated legacy Grid wrappers.
frontends/main/src/app-pages/OnboardingPage/OnboardingPage.tsx Updates item sizing syntax.
frontends/main/src/app-pages/LearningPathListingPage/LearningPathListingPage.tsx Simplifies layout using Grid2 directly.
frontends/main/src/app-pages/DashboardPage/ProfileContent.tsx Updates profile item sizing syntax.

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

@ahtesham-quraish ahtesham-quraish self-assigned this Sep 3, 2026

@ahtesham-quraish ahtesham-quraish left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM!

@ChristopherChudzicki
ChristopherChudzicki merged commit 5004314 into main Sep 4, 2026
16 checks passed
@ChristopherChudzicki
ChristopherChudzicki deleted the chudzick/mui-grid-v2-migration branch September 4, 2026 13:31
@odlbot odlbot mentioned this pull request Sep 7, 2026
10 tasks done
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Needs Review An open Pull Request that is ready for review

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants