Skip to content

Get started

Install one package, load one stylesheet, then use whichever layer fits your stack: CSS classes, custom elements or React.

Install

The umbrella package @kyralabs/m3exp-web re-exports every layer. Add @kyralabs/m3e-tokens as well so your package manager lets you import its icon stylesheets by path (pnpm only resolves direct dependencies).

npm install @kyralabs/m3exp-web @kyralabs/m3e-tokens

Pick a layer

The three component layers render the same DOM with the same classes, so they share one theme and mix on one page: a static card from CSS classes, a menu element inside it, a React date picker next to it.

LayerPackageUse it for
CSS classes @kyralabs/m3e-css Static components: buttons, cards, lists, chips, text fields, app bars. No JavaScript.
Custom elements @kyralabs/m3e-elements Behavior without a framework: menus, dialogs, sheets, pickers, springs and shape morphs. Zero dependencies, one entry per element.
React @kyralabs/m3e-react React apps: React Aria for behavior and accessibility, Motion for springs.
Tokens @kyralabs/m3e-tokens Always: the CSS custom properties every layer reads, the fonts, Material Symbols and seed themes.

Load the CSS

One import gives you the fonts, the tokens, the baseline theme and every component class. Icons are a separate stylesheet because the Material Symbols font is large.

@import '@kyralabs/m3exp-web/css/index.css'; /* fonts, tokens, baseline theme, every class */
@import '@kyralabs/m3e-tokens/material-symbols.css'; /* icons */

To ship less CSS, import the token stylesheets and only the components a page shows; each component file also works on its own:

@import '@kyralabs/m3e-tokens/fonts.css';
@import '@kyralabs/m3e-tokens/tokens.css';
@import '@kyralabs/m3e-tokens/theme.css';
@import '@kyralabs/m3e-css/icon.css';
@import '@kyralabs/m3e-css/button.css';
@import '@kyralabs/m3e-css/card.css';

Your first component

The same button in each layer:

<!-- CSS classes: no JavaScript -->
<button type="button" class="m3e-button m3e-button--filled m3e-button--size-m">
  <span class="m3e-icon" aria-hidden="true">save</span>
  Save
</button>
import { Button, Icon } from '@kyralabs/m3exp-web/react';

<Button variant="filled" size="m" icon={<Icon name="save" />} onPress={save}>
  Save
</Button>

The button has no custom element: CSS draws it completely, and React adds the press morph on a spring. Components whose behavior CSS cannot provide, such as menus, have an element:

<button id="more" type="button" class="m3e-icon-button" aria-label="More options">
  <span class="m3e-icon" aria-hidden="true">more_vert</span>
</button>
<m3e-menu anchor="more">
  <m3e-menu-item value="edit" icon="edit">Edit</m3e-menu-item>
  <m3e-menu-item value="share" icon="share">Share</m3e-menu-item>
</m3e-menu>

<script type="module">
  import '@kyralabs/m3exp-web/elements'; // registers every element
</script>

@kyralabs/m3exp-web/elements registers every element. To load only the ones a page uses, install @kyralabs/m3e-elements and import its per-element entries, such as @kyralabs/m3e-elements/menu.js; the Astro guide shows how.

Next steps