Skip to content

Component customization

Taking care when changing component HTML

Consider a simple <button> element with the label “Save”. The label tells us what the element does, but it’s also useful to know how it does it. If the element looks like a button, we can expect it to behave like one. That is, we’d expect it to make something happen, but not take us somewhere like a link should.

What about people who cannot see the button? Fortunately, the <button> element comes with a button role: it is identified as a button programmatically. Assistive technologies like screen readers will announce the role (what the <button> is) and the label (what it does) together: “save, button”.

Using the <button> element automatically provides the button role without additional code. It is, therefore, said to be an implicit role. However, you can change the role by either replacing the <button> with a different element, or by applying an explicit ARIA role attribute.

<!-- ❌ don't do this -->
<button role="link">Save</button>

This link is a lie. While it identifies its role as “link”, it still behaves as a button. In general, you should avoid overriding element roles in this way.

If you really wanted a link, you could use a link (anchor) element:

<!-- ❌ don't do this -->
<a>Save</a>

But that’s no good either. We’ve mismatched roles and behaviors again. Hitting “Save” does not take anyone anywhere, so there’s nothing to put in the href. And without an href, a link is not focusable or functional.

Each component comes with a Use cases section to help match roles with behaviors. However, sometimes component HTML needs to be updated to suit context, align with presentational convention, or signify state.

StrataKit lets you change the element used to render a component, via the render prop. This prop is available across the entire component catalog, in both StrataKit components and MUI components.

The Language and labels guide sets out the importance of applying the correct heading levels when describing the interface structure. Heading levels are set using the elements <h1> to <h6>.

The Typography component supports render for setting the element and variant for setting an accompanying style. This decoupling of semantics and style lets you set the correct structure while calibrating visual hierarchy.

In the following example, <h1> is the correct element, since it is the main heading for the page. But, since the context requires a diminished font-size, a headline-prefixed style is preferred over a larger display variant.

<Typography variant="headline-sm" render={<h1 />}>
Heading text
</Typography>

The render prop is capable of replacing not just HTML elements but React components.

Your application may use the popular React Router library and its Link component. However, you may wish to render React Router’s Link using the styling associated with the design system’s Link component.

Import React Router’s Link as an alias (e.g. RouterLink) and apply it using the render prop.

import Link from "@mui/material/Link";
import { Link as RouterLink } from "react-router";
export default () => {
return <Link render={<RouterLink to="/" />}>Home</Link>;
};

Some StrataKit components are also designed specifically to leverage the render prop. For example, the Toolbar uses this prop to render individual items as IconButtons.

Some more complex components, constituting subcomponents, support an object syntax for changing HTML elements through MUI’s slots and slotProps props.

Where needed, change your Accordion item’s heading via the heading slot:

<Accordion
variant="outlined"
role="listitem"
slots={{
heading: "h2",
}}
>

The slotProps alternative gives you finer grained control. For each element, you can set multiple props, including a render prop where applicable. For example, the NativeSelect’s input needs both name and id set:

<FormControl>
<InputLabel htmlFor={inputId}>Design system:</InputLabel>
<NativeSelect
defaultValue={2}
slotProps={{
input: {
name: "design-system",
id: inputId,
},
}}
>
<option value={1}>iTwinUI</option>
<option value={2}>StrataKit</option>
<option value={3}>Other</option>
</NativeSelect>
</FormControl>

The id is necessary for creating the association between the select element and its corresponding label. The id and htmlFor values must match.

It’s not always possible to ship all of the necessary semantic information as part of a component. As in the last example, some attribution must be applied during the assembly of your product interface. Study the component guides and examples carefully. These exemplify how to apply render and ARIA attribution to improve component accessibility and robustness.

Verify the correct semantic information is present by examining the rendered HTML code. To see what’s available in screen reader output specifically, examine the accessibility tree. In Chrome, you can view the accessibility tree by opening the inspector and choosing the accessibility tab (Elements > Accessibility).