
Introduction
Material UI (MUI) provides a powerful set of accessible components out of the box, but most real-world applications need custom behavior, branding, and layout adjustments. The challenge is extending or customizing MUI components without breaking accessibility.
Many teams unknowingly remove ARIA attributes, misconfigure roles, or introduce keyboard traps when customizing MUI. This article explores how to safely extend MUI components, build accessible custom components, and ensure your UI remains compliant with WCAG guidelines.
You’ll learn:
- How MUI handles accessibility internally
- How to override and extend components properly
- Patterns for accessible custom components
- Tools and workflows for testing accessibility
By the end, you’ll be able to build fully custom components while keeping your React apps inclusive and compliant.
1. Understanding MUI Accessibility Internals
MUI provides strong accessibility defaults:
- Proper ARIA roles for controls
- Keyboard navigation behavior
- Focus management for modals, menus, dialogs
- Labeling logic in form controls
- WCAG-aligned color contrast defaults
Example: MUI <Button> automatically handles role="button" and keyboard activation:
import { Button } from "@mui/material";
export default function Demo() {
return <Button variant="contained">Save</Button>;
}
When customizing, it’s essential to preserve or reapply these behaviors.
2. Extending MUI Components Safely
Using styled() API
import { styled } from "@mui/material/styles";
import Button from "@mui/material/Button";
const PrimaryButton = styled(Button)({
padding: "12px 20px",
fontWeight: 600,
borderRadius: "10px"
});
export default function Demo() {
return <PrimaryButton>Continue</PrimaryButton>;
}
Accessibility is preserved because the underlying component structure remains unchanged.
Using slotProps and componentsProps
For deeper customization:
<TextField
label="Email"
slotProps={{
inputLabel: { htmlFor: "email-field" },
input: { id: "email-field", "aria-required": "true" }
}}
/>
Avoid this anti-pattern
❌ Replacing MUI components with plain <div> containers:
// WRONG – removes button semantics
<div onClick={handleClick}>Save</div>
3. Building Custom Components from Scratch (MUI + ARIA)
Sometimes you need a fully custom component with MUI theme tokens.
Example: Accessible Toggle Switch
import { useState } from "react";
import { Box } from "@mui/material";
export default function AccessibleToggle() {
const [on, setOn] = useState(false);
return (
<Box
role="switch"
aria-checked={on}
tabIndex={0}
onClick={() => setOn(!on)}
onKeyDown={(e) => e.key === "Enter" && setOn(!on)}
sx={{
width: 50,
height: 24,
borderRadius: 12,
backgroundColor: on ? "primary.main" : "grey.500",
position: "relative",
cursor: "pointer"
}}
>
<Box
sx={{
width: 20,
height: 20,
borderRadius: "50%",
backgroundColor: "white",
position: "absolute",
top: 2,
left: on ? 28 : 2,
transition: "left 0.2s ease"
}}
/>
</Box>
);
}
Key accessibility notes:
role="switch"aria-checked- Supports keyboard interaction (
Enter) - Focusable (
tabIndex=0)
4. Testing Accessibility
Your custom MUI components should be tested with:
a) Axe DevTools (browser extension)
- Highlights missing labels
- Detects low contrast
- Flags role mismatches
b) Lighthouse Accessibility Audit
Run in Chrome DevTools → Audits.
c) Testing Library + jest-axe
import { render } from "@testing-library/react";
import { axe } from "jest-axe";
import AccessibleToggle from "./AccessibleToggle";
test("toggle is accessible", async () => {
const { container } = render(<AccessibleToggle />);
const results = await axe(container);
expect(results).toHaveNoViolations();
});
5. Common Pitfalls
❌ Removing keyboard navigation
For example, converting a MUI Button into a styled Box.
❌ Not forwarding refs
MUI relies on forwarded refs for focus management.
❌ Incorrect ARIA attributes
Avoid using ARIA roles when semantic HTML already provides them.
❌ Custom components without labels
Always link <label> and input via htmlFor.
Conclusion
Material UI gives you a strong accessibility foundation, but extending it requires care. By reusing MUI’s component structure, applying ARIA roles correctly, and testing with automated tools, you can create custom UI experiences without compromising inclusivity.
Accessible components improve usability for everyone—not just users with assistive technologies—and elevate the quality of your entire React application.