/Documentation

Getting started

PublishedUpdated

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 mtrl
npm install mtrl
pnpm add mtrl
yarn add mtrl

React, 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:

Vanilla
import { createButton } from 'mtrl';

const button = createButton({ text: 'Save', variant: 'filled' });
button.on('click', () => save());
document.body.append(button.element);
Web Components
<m-button variant="filled">Save</m-button>

<script type="module">
  const button = document.querySelector('m-button');
  button.addEventListener('click', () => save());
</script>
React
import { Button } from 'mtrl/react';
import { save } from './app';

export function Example() {
  return (
    <Button onClick={() => save()} variant="filled">Save</Button>
  );
}
Vue
<script setup lang="ts">
import { MButton } from 'mtrl/vue';
import { save } from './app';
</script>

<template>
  <MButton @click="save()" variant="filled">Save</MButton>
</template>
Svelte
<script lang="ts">
  import { Button } from 'mtrl/svelte';
  import { save } from './app';
</script>

<Button onclick={() => save()} variant="filled">Save</Button>
SolidJS
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.