mui/material-ui
Reviewed against Rams quality heuristics: accessibility, color, typography, spacing, components, motion, UX, and craft.
30 files reviewed·August 1, 2026
Elevated
Design risk in this codebase.
More findings
Verdict
Visual polish outpaces basic usability: gradients and scrims got attention that alt text and focus states didn't. The biggest risk is that assistive tech users hit unlabeled controls and invisible focus, undermining an otherwise systemic design.
Files Rams reviewed
docs/src/pages/premium-themes/onepirate/modules/views/ProductHeroLayout.tsx
docs/src/pages/premium-themes/onepirate/modules/components/Button.tsx
docs/src/pages/premium-themes/onepirate/modules/components/Markdown.tsx
docs/src/pages/premium-themes/onepirate/modules/components/Paper.tsx
docs/src/pages/premium-themes/onepirate/modules/components/Snackbar.tsx
docs/src/pages/premium-themes/onepirate/modules/components/TextField.tsx
docs/src/pages/premium-themes/onepirate/modules/components/Typography.tsx
docs/src/pages/premium-themes/onepirate/modules/views/AppAppBar.tsx
docs/src/pages/premium-themes/onepirate/modules/views/AppFooter.tsx
docs/src/pages/premium-themes/onepirate/modules/views/ProductCTA.tsx
docs/src/pages/premium-themes/onepirate/modules/views/ProductCategories.tsx
docs/src/pages/premium-themes/onepirate/modules/views/ProductHero.tsx
docs/src/pages/premium-themes/onepirate/modules/views/ProductHowItWorks.tsx
docs/src/pages/premium-themes/onepirate/modules/views/ProductValues.tsx
examples/material-ui-pigment-css-nextjs-ts/src/app/page.tsx
docs/src/pages/premium-themes/onepirate/modules/components/AppBar.tsx
docs/src/pages/premium-themes/onepirate/modules/components/Toolbar.tsx
docs/src/pages/premium-themes/onepirate/modules/views/AppForm.tsx
docs/src/pages/premium-themes/onepirate/modules/views/ProductSmokingHero.tsx
packages-internal/core-docs/src/AppLayout/components/EditPage.tsx
examples/material-ui-nextjs-ts/src/app/about/page.tsx
examples/material-ui-nextjs-ts/src/app/layout.tsx
examples/material-ui-nextjs-ts/src/app/page.tsx
examples/material-ui-pigment-css-nextjs-ts/src/app/layout.tsx
examples/material-ui-remix-ts/app/src/Layout.tsx
docs/data/material/getting-started/templates/crud-dashboard/components/DashboardLayout.tsx
docs/src/pages/premium-themes/onepirate/ForgotPassword.tsx
docs/src/pages/premium-themes/onepirate/SignIn.tsx
docs/src/pages/premium-themes/onepirate/SignUp.tsx
docs/src/pages/premium-themes/onepirate/modules/form/FormFeedback.tsx
Accessibility
examples/material-ui-pigment-css-nextjs-ts/src/app/page.tsx:40
Theme toggle button has no accessible name for screen readers
The IconButton at the top right of the hero swaps between "🌙" and "🔆" emoji as its only content, with no aria-label, title, or visually hidden text. Screen reader users hear "button" with no indication it toggles color scheme.
Why it matters
A screen reader user can't identify or operate the theme toggle at all, which locks them out of a control every sighted user can see and use.
Fix
Add an aria-label that describes the action the button performs.
<IconButton sx={{ fontSize: 20, px: 1.5 }} onClick={toggleColorScheme}>
{colorScheme === 'light' ? '🌙' : '🔆'}
</IconButton><IconButton
sx={{ fontSize: 20, px: 1.5 }}
onClick={toggleColorScheme}
aria-label={colorScheme === 'light' ? 'Switch to dark mode' : 'Switch to light mode'}
>
{colorScheme === 'light' ? '🌙' : '🔆'}
</IconButton>docs/src/pages/premium-themes/onepirate/modules/components/Button.tsx:12
Button strips its own focus ring with no replacement indicator
ButtonRoot sets boxShadow: 'none' as its base style, then reinforces it under '&:active, &:focus' with the same boxShadow: 'none'. Combined, keyboard focus produces zero visible change from the resting state.
Why it matters
A keyboard user tabbing through the page gets no visual confirmation this button is focused, so they can't tell where they are or whether Enter will activate it. This is a hard lockout for keyboard-only navigation.
Fix
Never remove focus-visible styling without substituting an equally visible replacement, such as an outline or ring.
'&:active, &:focus': {
boxShadow: 'none',
},'&:active': {
boxShadow: 'none',
},
'&:focus-visible': {
outline: `2px solid ${theme.palette.primary.main}`,
outlineOffset: 2,
},docs/src/pages/premium-themes/onepirate/modules/views/ProductHeroLayout.tsx:52
Hero image's alt text describes nothing about what it shows
The hero's leading <img> at the top of ProductHeroLayout has alt="wonder", a word describing a mood, not the image's content or purpose.
Why it matters
A screen reader user hears "wonder, image" with no way to know what's actually depicted, making the alt text functionally useless for anyone who can't see the image.
Fix
Write alt text that describes the image's actual content or the information it conveys, not an abstract mood word.
<img
src="/static/themes/onepirate/productHeroWonder.png"
alt="wonder"
width="147"
height="80"
/><img
src="/static/themes/onepirate/productHeroWonder.png"
alt="Decorative illustration of a pirate ship silhouette"
width="147"
height="80"
/>Craft
examples/material-ui-pigment-css-nextjs-ts/src/app/page.tsx:66
Gradient text-clip on "Material UI" headline sacrifices legibility for effect
The span wrapping "Material UI" inside the h1 uses a diagonal gradient with WebkitBackgroundClip: 'text' and WebkitTextFillColor: 'transparent', producing a gradient-filled headline rather than a solid, high-contrast color.
Why it matters
Gradient-clipped text has no guaranteed contrast ratio against the page background across its own range, and it reads as a templated stock effect rather than an intentional brand decision.
Fix
Use a solid theme color for headline text and reserve gradients for backgrounds or decorative surfaces, not foreground text.
background: `linear-gradient(145deg, ${(theme.vars || theme).palette.primary.light} 5%, ${(theme.vars || theme).palette.primary.dark} 90%)`,
WebkitBackgroundClip: 'text',
WebkitTextFillColor: 'transparent',color: (theme.vars || theme).palette.primary.dark,docs/src/pages/premium-themes/onepirate/modules/views/ProductHeroLayout.tsx:74
Arrow-down image sizing uses invalid unitless string values
The arrow-down image's sx sets height: '16' and width: '12' as strings with no unit. CSS requires a numeric length or unit; a bare number string like '16' is not a valid CSS length and the browser drops the declaration.
Why it matters
Without valid height/width, the image falls back to its natural pixel size instead of the intended 16x12 scroll-cue size, so the visual the developer coded for never actually renders.
Fix
Pass numeric values (interpreted by MUI's sx as px) instead of unitless strings.
sx={{ height: '16', width: '12', position: 'absolute', bottom: 32 }}sx={{ height: 16, width: 12, position: 'absolute', bottom: 32 }}Typography
Color
Spacing
Components
Motion
UX
Working well
- ProductHeroLayout's dark overlay Box at opacity: 0.5 sits behind the hero content as a deliberate scrim, guaranteeing legible contrast for text over an arbitrary background image rather than hoping the source photo is dark enough.
- Button.tsx builds padding and font size from theme.spacing() and theme.typography.pxToRem() rather than hardcoded pixel values, keeping the component on the design system's scale so a token change propagates automatically.
- The hero h1 uses fontSize: 'clamp(3rem, 2.354rem + 2.7562vw, 5rem)' paired with textWrap: 'balance', giving a display headline that scales fluidly across viewport widths and wraps cleanly without manual breakpoints.
Scored August 1, 2026 with Rams Engine v0.0.3 · Engine changelog
First scored July 29, 2026: 59/100. This rescore on v0.0.3: 59/100.
This page is an automated design review of mui/material-ui’s UI code: 30 files read against 291 versioned rules covering accessibility, color, typography, spacing, components, UX, motion, and craft. The score is out of 100; confirmed criticals cap it — one at 59, two at 49, three or more at 39.
More design scores
Score your own repo.
Free on public repos, no account. The same engine that scored this page reads your UI code and mints a score page like this one.
Public repos only. The full engine reviews the UI code and mints a public score page — we email you the link too. Already-scored repos open instantly.