Material 3 web components built with Stencil. More than 70 custom elements — buttons, text fields, dialogs, data tables — that style themselves from CSS custom properties and run in any page, with or without a framework.
Each component bundles its own CSS into its shadow root. The only stylesheet you
load is a theme file of --md-sys-color-* tokens — with one exception:
material-data-table and material-breadcrumbs enhance real light-DOM markup
(a server-rendered <table>, a real <nav>) rather than a shadow root, so
their styling ships as a second, optional stylesheet (material.css). There
is no runtime stylesheet fetch and no build step for consumers.
npm install @viewflow/materialOr load it from a CDN with no install:
<script type="module" src="https://unpkg.com/@viewflow/material"></script>A page needs three things: the theme stylesheet, a theme class on <html>, and
the Material Symbols font.
<html lang="en" class="light">
<head>
<link rel="stylesheet" href="https://unpkg.com/@viewflow/material/css/theme.css">
<link rel="stylesheet"
href="https://fonts.googleapis.com/css2?family=Material+Symbols+Outlined:opsz,wght,FILL,GRAD@24,400,0,0">
<script type="module" src="https://unpkg.com/@viewflow/material"></script>
</head>
<body>
<material-button variant="filled" label="It works" icon="check"></material-button>
</body>
</html>theme.csscarries the--md-sys-color-*custom properties. They cascade into every shadow tree, so components render themed with no per-component setup.- The
<html>class picks the theme:light,dark, or one of the four contrast variants. No class means no tokens. - The Material Symbols font renders the
icon="..."ligatures. Without it, icons show as their text names.
Using material-data-table or material-breadcrumbs? Add
@viewflow/material/material.css next to theme.css — see
Light-DOM components.
| Method | Source | Use it when |
|---|---|---|
| Single bundle | unpkg.com/@viewflow/material (~590 KB, all elements eager) |
You want one file and use many components. |
| Lazy loader | .../dist/material/material.esm.js (small entry) |
A page uses a few components; chunks load on demand. |
With a bundler:
import { defineCustomElements } from '@viewflow/material/loader';
import '@viewflow/material/theme.css';
defineCustomElements();Or import only the elements you use. Each one registers itself:
import '@viewflow/material/dist/components/material-button.js';- Self-contained styles. No stylesheet to fetch, no adopted-stylesheet wiring, no flash of unstyled content. A component renders correctly the moment it upgrades.
- Form association. Put a field in a
<form>with anameand it posts its value, runs constraint validation (required,checkValidity(),reportValidity()), and resets with the form. No hidden inputs. - Server-first. Components enhance server-rendered markup, such as a real
<table>insidematerial-data-tableor a real<form>post, instead of owning a client-side data model. - Plain events. Every interaction is a
CustomEventyou read withaddEventListener(valueChange,materialSort, …). - RTL and i18n. Set
dir="rtl"on any subtree and layout, animation, and keyboard direction follow. Strings and formats come from yourgettextandIntl, English by default. - Accessibility. Keyboard navigation, focus rings, 48dp touch targets,
Windows High Contrast, and
prefers-reduced-motionare built in.
| Group | Elements | Reference |
|---|---|---|
| Actions | button, icon-button, fab, fab-menu, split-button, button-group, chip, chip-set | actions.md |
| Text fields | textfield, textarea, number-field, masked-field, date-field, time-field, datetime-field, date-range-field, file-field, json-field | fields.md |
| Selection | checkbox, radio, switch, slider, select, autocomplete, dropzone | forms.md |
| Navigation | app-bar, toolbar, navigation-bar, navigation-rail, navigation-group, navigation-item, tabs, breadcrumbs, pagination, stepper | navigation.md |
| Overlays | dialog, bottom-sheet, side-sheet, menu, tooltip, snackbar, command-palette | overlays.md |
| Data & display | data-table, list, card, avatar, badge, divider, tree, transfer, calendar, carousel, rich-text, time-picker | display.md, data-table.md, lists.md |
| Progress | linear-progress, circular-progress, loading-indicator, skeleton | progress.md |
| Search | search, search-app-bar | search.md |
Tags and attributes are kebab-case (<material-date-field first-day-of-week="1">).
Boolean attributes follow HTML rules: present means true.
theme.css holds the tokens from
Material Theme Builder,
scoped to six classes: light, dark, and a medium- and high-contrast variant of
each. Switch themes by changing the <html> class.
To use your own palette, export a new set from the builder (Export → Web → CSS),
replace the six files in src/theme/, and rebuild. Component code never changes,
because every element reads the same --md-sys-color-* names. See
theming.md.
material-data-table and material-breadcrumbs enhance real server-rendered
markup — a <table>, a <nav> — instead of owning a shadow root, so their
styling can't be bundled into a JS chunk the way every other component's is.
It ships as material.css, loaded the same way as theme.css:
<link rel="stylesheet" href="https://unpkg.com/@viewflow/material/css/theme.css">
<link rel="stylesheet" href="https://unpkg.com/@viewflow/material/css/material.css">Skip it and the rest of the library still works — only these two render unstyled. Any future component built the same server-first way (enhancing markup that has to exist without JS) joins this file rather than getting its own.
Each area has a reference under skills/material-web-components/references/:
- setup.md — loading the library on a page
- theming.md — tokens and palettes
- forms.md / fields.md — form controls and validation
- navigation.md, overlays.md, display.md, lists.md, data-table.md, progress.md, search.md, stepper.md
- i18n.md — catalogs and formats
- integrations.md — what you wire up (endpoints, persistence, file upload, maps)
Build from source and run the dev server:
git clone https://github.com/viewflow/material
cd material && npm install
npm start # http://localhost:3333npm start runs three watchers: theme bundling, Tailwind for the demo pages, and
Stencil's dev server. Every component has a demo page at
src/demos/<component>.html, which is where behavior is checked. There are no unit
tests; the components are mostly CSS, so demo pages carry the test cases.
Build the package:
npm run build # theme.css + material.css + Stencil dist/ + single-file CDN bundlenpm publish runs this build first through prepublishOnly.
Add a component:
npx stencil generate material-cardKeep each component's styles in its own shadow root and read var(--md-sys-color-*)
directly — src/global/material.css is a Tailwind entry for the demo and
showcase pages, plus the source npm run build:material:pkg reads to produce
the published css/material.css (see Light-DOM components
above). A component's own shadow-DOM styles never depend on it; only the two
light-DOM components it @imports under layer(components) do.
@viewflow/material is an Open Source project. It uses the AGPL license,
The GNU Affero General Public License v3.0,
with the additional permissions in LICENSE_EXCEPTION.
The exception permits you to use this package in a project that has a license which is not compatible with the AGPL. A proprietary project is included. Your own code keeps your own license, and you do not release its source. The condition is that you do not change the source code of this package — importing the components, styling them through CSS custom properties, and shipping the bundle as-is all stay within the exception.
If you do change this package, the AGPL applies to your modified version of it.
The license scheme is the same as the license scheme of the GCC Runtime Library. The text above is a summary. Read LICENSE_EXCEPTION for the conditions.