mantinedev/mantine
Reviewed against Rams quality heuristics: accessibility, color, typography, spacing, components, motion, UX, and craft.
30 files reviewed·July 14, 2026
Elevated
Design risk in this codebase.
More findings
Verdict
Solid Mantine plumbing hides a rookie accessibility mistake baked into every page load. The viewport meta tag disables pinch-zoom sitewide, a one-line fix that would meaningfully lift this score.
Files Rams reviewed
apps/help.mantine.dev/src/components/MdxLayout/MdxLayout.tsx
apps/mantine.dev/src/components/HomePage/HomePage.tsx
apps/help.mantine.dev/src/pages/_app.tsx
apps/mantine.dev/src/components/MdxLayout/MdxLayout.tsx
apps/mantine.dev/src/components/MdxPage/MdxPage.tsx
apps/mantine.dev/src/pages/_app.tsx
apps/mantine.dev/src/pages/_document.tsx
apps/help.mantine.dev/src/components/MdxElements/MdxElements.tsx
apps/help.mantine.dev/src/components/MdxElements/MdxInfo/MdxInfo.module.css
apps/help.mantine.dev/src/components/MdxElements/MdxNpmScript/MdxNpmScript.tsx
apps/help.mantine.dev/src/components/MdxLayout/TableOfContents/TableOfContents.module.css
apps/help.mantine.dev/src/components/MdxLayout/TableOfContents/TableOfContents.tsx
apps/help.mantine.dev/src/components/QuestionsList/QuestionsList.tsx
apps/help.mantine.dev/src/components/QuestionsList/QuestionsListGroup/QuestionsListGroup.tsx
apps/help.mantine.dev/src/components/QuestionsList/QuestionsListHeader/QuestionsListHeader.tsx
apps/help.mantine.dev/src/components/Shell/Shell.tsx
apps/help.mantine.dev/src/components/SocialCards/SocialCards.module.css
apps/help.mantine.dev/src/components/SocialCards/SocialCards.tsx
apps/help.mantine.dev/src/pages/index.tsx
apps/mantine.dev/src/components/Banner/Banner.module.css
apps/mantine.dev/src/components/Banner/Banner.tsx
apps/mantine.dev/src/components/ColorsGenerator/ColorsGenerator.tsx
apps/mantine.dev/src/components/ColorsGenerator/ColorsInput/ColorsInput.tsx
apps/mantine.dev/src/components/ColorsGenerator/ColorsList/ColorsList.module.css
apps/mantine.dev/src/components/ColorsGenerator/ColorsList/ColorsList.tsx
apps/mantine.dev/src/components/ColorsGenerator/ColorsOutput/ColorsOutput.tsx
apps/mantine.dev/src/components/ColorsGenerator/ComponentsPreview/ComponentsPreview.tsx
apps/mantine.dev/src/components/CssFilesList/CssFilesList.tsx
apps/mantine.dev/src/components/CssVariablesGroup/CssVariablesGroup.tsx
apps/mantine.dev/src/components/CssVariablesList/CssVariablesList.tsx
Accessibility
apps/help.mantine.dev/src/pages/_app.tsx:42
Viewport meta blocks pinch-zoom for every visitor to the help center
The `<meta name="viewport">` tag sets `user-scalable=no` alongside `minimum-scale=1, initial-scale=1`. This disables pinch-to-zoom on any mobile browser that honors the cap.
Why it matters
Low-vision users lose the ability to zoom the entire page, not just an input field, on every browser except iOS Safari (which ignores the cap). This fails WCAG 2.1.1 and locks out a real class of users on a docs site meant to be read.
Fix
Remove user-scalable=no and maximum-scale caps from the viewport meta; fix any iOS input-zoom issue by setting 16px font on inputs instead.
<meta
name="viewport"
content="minimum-scale=1, initial-scale=1, width=device-width, user-scalable=no"
/><meta
name="viewport"
content="minimum-scale=1, initial-scale=1, width=device-width"
/>apps/help.mantine.dev/src/components/MdxLayout/MdxLayout.tsx:51
The <time> element's dateTime attribute is not machine-readable
The "Last updated" timestamp renders `meta.last_updated_at` as visible text, but the wrapping `<Text component="time" dateTime={new Date(meta.last_updated_at).toLocaleDateString()}>` feeds the dateTime attribute a locale-formatted string (e.g. "1/15/2024") instead of a valid ISO 8601 date.
Why it matters
The dateTime attribute exists specifically so assistive tech and search crawlers can parse the date programmatically; a locale string isn't a valid datetime per the HTML spec, so that machine-readable meaning is silently lost for every article on the help site.
Fix
Feed the dateTime attribute a valid ISO 8601 string, independent of how the visible text is formatted.
dateTime={new Date(meta.last_updated_at).toLocaleDateString()}dateTime={new Date(meta.last_updated_at).toISOString()}Typography
apps/mantine.dev/src/pages/_document.tsx:10
Google Fonts loaded via CDN link instead of self-hosted next/font
The `<Head>` block loads Outfit through a `fonts.googleapis.com` stylesheet link with two preconnect hints, rather than `next/font/google`, which this Next.js app has available.
Why it matters
The browser must resolve and fetch a second origin before the font renders, adding a full round-trip to first paint, and it sends visitor data to Google's CDN on every load.
Fix
Self-host the font with next/font/google so it's bundled and served from the same origin with no extra round-trip.
<link rel="preconnect" href="https://fonts.googleapis.com" />
<link rel="preconnect" href="https://fonts.gstatic.com" crossOrigin="" />
<link
href="https://fonts.googleapis.com/css2?family=Outfit:wght@100..900&display=swap"
rel="stylesheet"
/>{/* Load via next/font/google in _app or a shared layout instead:
import { Outfit } from 'next/font/google';
const outfit = Outfit({ subsets: ['latin'], display: 'swap' }); */}Want this on your repo?
Rams reviews your next PR automatically and posts inline fix suggestions.
Review my public repo for freeComponents
apps/mantine.dev/src/pages/_document.tsx:9
Color scheme hardcoded to light with no dark-mode wiring visible
`<Html data-mantine-color-scheme="light">` and `<ColorSchemeScript defaultColorScheme="light">` both hardcode light mode, with no `color-scheme` meta or CSS property set for browser chrome.
Why it matters
If this app supports a dark theme elsewhere, users toggling it get mismatched native browser UI (scrollbars, form controls) that stays light while the page goes dark.
Fix
Set color-scheme to match the active theme, or confirm the app is light-only and drop the scaffolding for dark mode.
<Html lang="en" data-mantine-color-scheme="light"><Html lang="en" data-mantine-color-scheme="light" style={{ colorScheme: 'light' }}>UX
apps/help.mantine.dev/src/pages/_app.tsx:14
Shiki highlighter has no loading or error path before code blocks render
`createShikiAdapter(loadShiki)` wires an async dynamic import (`await import('shiki')`) directly into `CodeHighlightAdapterProvider` with no visible fallback for the load or failure state.
Why it matters
If the dynamic import is slow or fails (network hiccup, CDN issue), every code block on the help site has no defined fallback rendering, and users see either a blank block or an unhandled error instead of raw code.
Fix
Handle the shiki load rejection and provide a plain-text fallback rendering path for code blocks.
async function loadShiki() {
const { createHighlighter } = await import('shiki');
const shiki = await createHighlighter({
langs: ['tsx', 'scss', 'html', 'bash', 'json'],
themes: [],
});
return shiki;
}async function loadShiki() {
try {
const { createHighlighter } = await import('shiki');
return await createHighlighter({
langs: ['tsx', 'scss', 'html', 'bash', 'json'],
themes: [],
});
} catch (error) {
console.error('Failed to load Shiki highlighter', error);
throw error;
}
}Craft
apps/help.mantine.dev/src/pages/_app.tsx:26
App component props typed as any hides prop mismatches until runtime
`export default function App({ Component, pageProps }: any)` casts the entire props object to `any` instead of using Next.js's `AppProps` type.
Why it matters
Typos or mismatched props for `Component` or `pageProps` won't be caught at compile time; a future refactor can silently break page rendering and the failure only shows up as a broken UI in production.
Fix
Use Next.js's built-in AppProps type instead of any.
export default function App({ Component, pageProps }: any) {export default function App({ Component, pageProps }: AppProps) {Color
Spacing
Motion
Working well
- Centralizing all social/meta tags (og:title, twitter:title, description, keywords) in one Head block inside _app.tsx keeps every page's document metadata consistent without duplicating tags per-page: a solid pattern for a docs/help site where every page should carry the same brand identity.
- Wrapping the entire app in a single MantineProvider with a shared `theme` object at the root, rather than per-page providers, is the correct place for a global design-token source of truth: it guarantees every page pulls from one palette and spacing scale instead of drifting per route.
- The provider tree is composed cleanly and in a sensible order: DirectionProvider wraps MantineEmotionProvider wraps MantineProvider wraps the code highlight and modals providers, so theme, direction, and styling concerns are layered predictably rather than tangled into one component.
- The back link uses Anchor's own `underline="hover"` prop instead of a custom hover class or inline color override: this is the correct way to extend a design-system primitive, since the hover behavior stays centralized in one component instead of being reinvented per instance.
Score your own repo with Rams.
Free on public repos. Rams reviews every pull request for accessibility, color, type, spacing, components, motion, UX, and craft, and posts inline fixes.