Getting started
mtrl is a Material Design 3 component library for the web, with no dependencies. The same components work as plain JavaScript factories, as web components, and as React, Vue, Svelte and SolidJS components. This page takes you from install to a first component; the switch at the top shows every example in the way you use it.
Install
bun add mtrlnpm install mtrlpnpm add mtrlyarn add mtrlReact, Vue, Svelte and SolidJS are optional peer dependencies: mtrl uses the one your app already has, and installs none of them itself.
Choose how to use it
| Way | Import from | Good for |
|---|---|---|
| Vanilla | mtrl |
The smallest bundles, full control, any stack |
| Web Components | mtrl/elements |
Plain HTML, server templates, any framework |
| React | mtrl/react |
React 18 and 19, Next.js |
| Vue | mtrl/vue |
Vue 3, Nuxt |
| Svelte | mtrl/svelte |
Svelte 5, SvelteKit |
| SolidJS | mtrl/solid |
SolidJS, SolidStart |
The web components are built on the factories, and the framework components render the web components, so they all look and behave alike.
Each web component styles its own shadow root, which costs more on a first render than the same component as a factory: 1,000 text fields take about twice as long to style (roughly 300 ms against 150 ms on a slow phone's CPU), comparable to Material Web's. That is invisible for a form or a page, but for hundreds of instances at once, such as a long editable table, the Vanilla factories are the faster choice. See Web Components.
Add the styles
Every app imports the base stylesheet once: the colour, type and shape tokens, and the ripple.
import 'mtrl/styles/base';
With the Vanilla factories, also import each component's stylesheet:
import 'mtrl/styles/button';
The web components and the framework components carry their own styles in their shadow roots, so the base stylesheet is all they need. With web components, register them once:
import 'mtrl/elements/css';
import { defineAll } from 'mtrl/elements';
defineAll();
The React, Vue, Svelte and SolidJS components register the element they render the first time it mounts.
A first component
A filled button that saves when it is clicked:
import { createButton } from 'mtrl';
const button = createButton({ text: 'Save', variant: 'filled' });
button.on('click', () => save());
document.body.append(button.element);
<m-button variant="filled">Save</m-button>
<script type="module">
const button = document.querySelector('m-button');
button.addEventListener('click', () => save());
</script>
import { Button } from 'mtrl/react';
import { save } from './app';
export function Example() {
return (
<Button onClick={() => save()} variant="filled">Save</Button>
);
}
<script setup lang="ts">
import { MButton } from 'mtrl/vue';
import { save } from './app';
</script>
<template>
<MButton @click="save()" variant="filled">Save</MButton>
</template>
<script lang="ts">
import { Button } from 'mtrl/svelte';
import { save } from './app';
</script>
<Button onclick={() => save()} variant="filled">Save</Button>
import { Button } from 'mtrl/solid';
import { save } from './app';
export function Example() {
return (
<Button onClick={() => save()} variant="filled">Save</Button>
);
}
Every component page has the same kind of example, and a playground to try the options.
Themes and dark mode
The base stylesheet has the baseline theme. Another theme is one more import, and it applies to the element that names it, usually the whole page:
import 'mtrl/themes/vibrant';
document.documentElement.dataset.theme = 'vibrant';
document.documentElement.dataset.themeMode = 'dark';
Browse the themes and every colour role in Styles › Color, and see Theming to make your own.
Next steps
- Components: every component in a playground, with the code for your framework.
- The guide for your framework, for its events, forms and server rendering.
- Architecture: how mtrl is built.
- Examples: whole screens in all six flavours.