Mantine's internal styling
case study: Mantine's implementation of Button
The Button source code includes the typescript file (Button.tsx) and the stylesheet (Button.module.css).
HTML element structure
There are several, nested elements:
- the root button is the top level container.
- the inner span is an intermediate container for the label and the sections
- a section is a container for an icon.
- the label span contains the button's text.
- the loader span is an intermediate container for a loader.
/* root */
<button>
{/* 1.0 loader container*/}
<span />
{/* 2.0 inner */}
<span>
{/* 2.1 section */}
<span>
<svg /> {/* 2.1.0 icon */}
</span>
{/* 2.2 label */}
<span>{/* 2.2.0 text */}</span>
</span>
</button>
Both the mantine-implemented internal classes and empty classes are present, on each inner-element:
<button class="m-77c9d27d mantine-Button-root .." ..>
<span class="m-80f1301b mantine-Button-inner">
<span class="m-811560b9 mantine-Button-label">
Save
</span>
</span>
</button>
some inner-elements have some data-attributes, which may be shared across inner-elements of distinct components, such as the mantine-active and mantine-focus-auto attributes.
For example, mantine-active allows to receive style that activates when the element is active. The attribute is always there, and the stylesheet discriminates to the :active state.
mantine-active:active {
transform: translateY(calc(0.0625rem));
}
Button's stylesheet
The stylesheet is a CSS module and follows the pattern where classes are named after inner-elements of the Button component. We reproduce parts of the root class.
The .tsx file imports the CSS module.
style shipped on npm
the style is mostly the same. It is probably processed by PostCSS. It does not use CSS nesting.
It is then processed even more and merged to a gigantic 232kb stylesheet, shipped on npm too, the one we import from our app.