Try Live
Add Docs
Rankings
Pricing
Enterprise
Docs
Install
Theme
Install
Docs
Pricing
Enterprise
More...
More...
Try Live
Rankings
Create API Key
Add Docs
Material Web
https://github.com/material-components/material-web
Admin
A library of web components that helps build beautiful and accessible web applications using
...
Tokens:
81,122
Snippets:
720
Trust Score:
7.9
Update:
2 weeks ago
Context
Skills
Chat
Benchmark
85.4
Suggestions
Latest
Show doc for...
Code
Info
Show Results
Context Summary (auto-generated)
Raw
Copy
Link
# Material Web Components (@material/web) Material Web is Google's official implementation of Material Design 3 (M3) as web components. Built with Lit, it provides a comprehensive library of accessible, customizable UI components that work across all modern browsers and frameworks. The library delivers Material Design's expressive visual language through native web platform standards, enabling developers to create cohesive, beautiful user interfaces without framework lock-in. The components follow the Web Components specification, utilizing Custom Elements, Shadow DOM, and CSS Custom Properties (design tokens) for encapsulation and theming. Material Web emphasizes accessibility with built-in ARIA support, keyboard navigation, and form participation. All components integrate seamlessly with native HTML forms and can be themed using CSS custom properties that map to Material Design's token system for colors, typography, and shapes. ## Installation Install Material Web components via npm and import the components you need. ```bash npm install @material/web ``` ```javascript // Import specific components import '@material/web/button/filled-button.js'; import '@material/web/button/outlined-button.js'; import '@material/web/textfield/filled-text-field.js'; import '@material/web/checkbox/checkbox.js'; // Use in HTML // <md-filled-button>Click me</md-filled-button> ``` ## Button Components Buttons help users take actions and make choices with a single tap. Material Web provides filled, outlined, elevated, filled-tonal, and text button variants for different emphasis levels. ```html <!-- Filled button - highest emphasis for primary actions --> <md-filled-button>Submit</md-filled-button> <!-- Outlined button - medium emphasis --> <md-outlined-button>Cancel</md-outlined-button> <!-- Elevated button - for actions needing more visual separation --> <md-elevated-button>Upload</md-elevated-button> <!-- Filled tonal button - secondary actions with less emphasis --> <md-filled-tonal-button>Save draft</md-filled-tonal-button> <!-- Text button - lowest emphasis for less critical actions --> <md-text-button>Learn more</md-text-button> <!-- Button with icon --> <md-filled-button> <md-icon slot="icon">send</md-icon> Send message </md-filled-button> <!-- Link button - navigates to URL --> <md-filled-button href="https://example.com" target="_blank"> Visit site </md-filled-button> <!-- Disabled states --> <md-filled-button disabled>Disabled</md-filled-button> <md-filled-button soft-disabled>Soft disabled (focusable)</md-filled-button> <!-- Event handling --> <script> const button = document.querySelector('md-filled-button'); button.addEventListener('click', () => { console.log('Button clicked!'); }); </script> ``` ## Text Field Components Text fields allow users to enter and edit text. They come in filled and outlined variants with support for labels, helper text, error states, and input types. ```html <!-- Filled text field --> <md-filled-text-field label="Email address" type="email" placeholder="you@example.com" supporting-text="We'll never share your email"> </md-filled-text-field> <!-- Outlined text field --> <md-outlined-text-field label="Username" required minlength="3" maxlength="20"> </md-outlined-text-field> <!-- Password field with toggle visibility --> <md-filled-text-field label="Password" type="password"> </md-filled-text-field> <!-- Text field with error state --> <md-filled-text-field label="Phone number" type="tel" error error-text="Please enter a valid phone number"> </md-filled-text-field> <!-- Textarea for multiline input --> <md-outlined-text-field label="Message" type="textarea" rows="4"> </md-outlined-text-field> <!-- Text field with icons --> <md-filled-text-field label="Search"> <md-icon slot="leading-icon">search</md-icon> <md-icon-button slot="trailing-icon"> <md-icon>clear</md-icon> </md-icon-button> </md-filled-text-field> <!-- Form integration --> <form id="signup-form"> <md-filled-text-field name="email" label="Email" type="email" required> </md-filled-text-field> <md-filled-button type="submit">Sign up</md-filled-button> </form> <script> const form = document.getElementById('signup-form'); form.addEventListener('submit', (e) => { e.preventDefault(); const formData = new FormData(form); console.log('Email:', formData.get('email')); }); </script> ``` ## Checkbox Component Checkboxes allow users to select one or more items from a set or toggle options on and off. They support checked, unchecked, and indeterminate states. ```html <!-- Basic checkbox --> <md-checkbox touch-target="wrapper"></md-checkbox> <!-- Pre-checked checkbox --> <md-checkbox touch-target="wrapper" checked></md-checkbox> <!-- Indeterminate state (for parent selections) --> <md-checkbox touch-target="wrapper" indeterminate></md-checkbox> <!-- Checkbox with label using wrapper --> <label> <md-checkbox touch-target="wrapper"></md-checkbox> I agree to the terms and conditions </label> <!-- Checkbox with label using for attribute --> <md-checkbox id="notifications" touch-target="wrapper" aria-label="Enable notifications"></md-checkbox> <label for="notifications">Enable email notifications</label> <!-- Required checkbox in form --> <form> <label> <md-checkbox name="terms" value="accepted" required aria-label="Accept terms"> </md-checkbox> Accept terms and conditions </label> <md-filled-button type="submit">Continue</md-filled-button> </form> <!-- Handle checkbox changes --> <script> const checkbox = document.querySelector('md-checkbox'); checkbox.addEventListener('change', (e) => { console.log('Checked:', e.target.checked); }); </script> ``` ## Switch Component Switches toggle the state of a single item on or off, similar to a physical toggle switch. They're ideal for settings that take effect immediately. ```html <!-- Basic switch --> <md-switch></md-switch> <!-- Pre-selected switch --> <md-switch selected></md-switch> <!-- Switch with icons --> <md-switch icons></md-switch> <md-switch icons selected></md-switch> <!-- Show only selected icon --> <md-switch icons show-only-selected-icon></md-switch> <!-- Switch with label --> <label> Wi-Fi <md-switch selected aria-label="Wi-Fi"></md-switch> </label> <label for="bluetooth">Bluetooth</label> <md-switch id="bluetooth" aria-label="Bluetooth"></md-switch> <!-- Form integration --> <form id="settings-form"> <label> Dark mode <md-switch name="darkMode" value="enabled" aria-label="Dark mode"></md-switch> </label> <md-filled-button type="submit">Save</md-filled-button> </form> <script> const darkModeSwitch = document.querySelector('md-switch'); darkModeSwitch.addEventListener('change', (e) => { document.body.classList.toggle('dark-theme', e.target.selected); }); </script> ``` ## Radio Button Component Radio buttons let users select one option from a set of mutually exclusive options. Radios with the same name form a group where only one can be selected. ```html <!-- Radio button group --> <form> <div role="radiogroup" aria-labelledby="size-label"> <h3 id="size-label">Select size</h3> <md-radio id="small" name="size" value="small" aria-label="Small"></md-radio> <label for="small">Small</label> <md-radio id="medium" name="size" value="medium" checked aria-label="Medium"></md-radio> <label for="medium">Medium</label> <md-radio id="large" name="size" value="large" aria-label="Large"></md-radio> <label for="large">Large</label> </div> <md-filled-button type="submit">Confirm</md-filled-button> </form> <!-- Handle radio selection --> <script> const radios = document.querySelectorAll('md-radio[name="size"]'); radios.forEach(radio => { radio.addEventListener('change', (e) => { if (e.target.checked) { console.log('Selected size:', e.target.value); } }); }); </script> ``` ## Select Component Select menus display a list of choices on temporary surfaces, letting users pick one option from a fixed list. Available in filled and outlined variants. ```html <!-- Outlined select --> <md-outlined-select label="Choose a fruit"> <md-select-option aria-label="blank"></md-select-option> <md-select-option selected value="apple"> <div slot="headline">Apple</div> </md-select-option> <md-select-option value="banana"> <div slot="headline">Banana</div> </md-select-option> <md-select-option value="orange"> <div slot="headline">Orange</div> </md-select-option> </md-outlined-select> <!-- Filled select --> <md-filled-select label="Country" required> <md-select-option value="us"> <div slot="headline">United States</div> </md-select-option> <md-select-option value="uk"> <div slot="headline">United Kingdom</div> </md-select-option> <md-select-option value="ca"> <div slot="headline">Canada</div> </md-select-option> </md-filled-select> <!-- Select with supporting text and error --> <md-filled-select label="Priority" supporting-text="Select task priority" error-text="Please select a priority level"> <md-select-option value="low"> <div slot="headline">Low</div> </md-select-option> <md-select-option value="medium"> <div slot="headline">Medium</div> </md-select-option> <md-select-option value="high"> <div slot="headline">High</div> </md-select-option> </md-filled-select> <!-- Handle selection changes --> <script> const select = document.querySelector('md-outlined-select'); select.addEventListener('change', (e) => { console.log('Selected value:', e.target.value); }); // Programmatic selection select.select('banana'); // Or by index select.selectIndex(2); </script> ``` ## Menu Component Menus display a list of choices on temporary surfaces, typically triggered by buttons. They support nested submenus, keyboard navigation, and typeahead functionality. ```html <!-- Basic menu with anchor --> <span style="position: relative"> <md-filled-button id="menu-anchor">Open menu</md-filled-button> <md-menu id="main-menu" anchor="menu-anchor"> <md-menu-item> <div slot="headline">Cut</div> </md-menu-item> <md-menu-item> <div slot="headline">Copy</div> </md-menu-item> <md-menu-item> <div slot="headline">Paste</div> </md-menu-item> <md-divider></md-divider> <md-menu-item> <div slot="headline">Delete</div> </md-menu-item> </md-menu> </span> <script> const anchor = document.getElementById('menu-anchor'); const menu = document.getElementById('main-menu'); anchor.addEventListener('click', () => { menu.open = !menu.open; }); // Handle menu item selection menu.addEventListener('close-menu', (e) => { console.log('Selected:', e.detail.initiator?.textContent); }); </script> <!-- Menu with submenus --> <span style="position: relative"> <md-filled-button id="submenu-anchor">Menu with submenus</md-filled-button> <md-menu has-overflow id="submenu-menu" anchor="submenu-anchor"> <md-sub-menu> <md-menu-item slot="item"> <div slot="headline">Share</div> <md-icon slot="end">arrow_right</md-icon> </md-menu-item> <md-menu slot="menu"> <md-menu-item> <div slot="headline">Email</div> </md-menu-item> <md-menu-item> <div slot="headline">Twitter</div> </md-menu-item> <md-menu-item> <div slot="headline">LinkedIn</div> </md-menu-item> </md-menu> </md-sub-menu> <md-menu-item> <div slot="headline">Download</div> </md-menu-item> </md-menu> </span> <!-- Popover-positioned menu (renders above all content) --> <md-menu positioning="popover" id="popover-menu" anchor="some-anchor"> <md-menu-item> <div slot="headline">Option 1</div> </md-menu-item> <md-menu-item> <div slot="headline">Option 2</div> </md-menu-item> </md-menu> ``` ## Dialog Component Dialogs provide important prompts in a user flow, displaying critical information or requesting decisions. They support headlines, content, and action buttons. ```html <!-- Basic dialog --> <md-dialog id="confirm-dialog"> <div slot="headline">Confirm action</div> <form slot="content" id="dialog-form" method="dialog"> Are you sure you want to delete this item? This action cannot be undone. </form> <div slot="actions"> <md-text-button form="dialog-form" value="cancel">Cancel</md-text-button> <md-filled-button form="dialog-form" value="confirm">Delete</md-filled-button> </div> </md-dialog> <md-filled-button id="open-dialog-btn">Delete item</md-filled-button> <script> const dialog = document.getElementById('confirm-dialog'); const openBtn = document.getElementById('open-dialog-btn'); openBtn.addEventListener('click', () => { dialog.show(); }); dialog.addEventListener('close', () => { if (dialog.returnValue === 'confirm') { console.log('Item deleted'); } else { console.log('Deletion cancelled'); } }); </script> <!-- Alert dialog (for important messages requiring response) --> <md-dialog type="alert" id="error-dialog"> <div slot="headline">Error</div> <form slot="content" id="error-form" method="dialog"> An error occurred while saving. Please try again. </form> <div slot="actions"> <md-filled-button form="error-form" value="ok">OK</md-filled-button> </div> </md-dialog> <!-- Dialog without headline (needs aria-label) --> <md-dialog aria-label="Network error notification"> <div slot="content">Connection lost. Reconnecting...</div> </md-dialog> <!-- Programmatic open/close with animations --> <script> // show() and close() return Promises that resolve after animations await dialog.show(); console.log('Dialog is now fully open'); await dialog.close('confirmed'); console.log('Dialog is now fully closed'); </script> ``` ## Tabs Component Tabs organize groups of related content at the same hierarchy level. Primary tabs appear at the top under app bars; secondary tabs provide further organization within content areas. ```html <!-- Primary tabs --> <md-tabs id="main-tabs"> <md-primary-tab>Videos</md-primary-tab> <md-primary-tab active>Photos</md-primary-tab> <md-primary-tab>Music</md-primary-tab> </md-tabs> <!-- Secondary tabs --> <md-tabs> <md-secondary-tab>All</md-secondary-tab> <md-secondary-tab>Recent</md-secondary-tab> <md-secondary-tab>Favorites</md-secondary-tab> </md-tabs> <!-- Tabs with icons --> <md-tabs> <md-primary-tab> <md-icon slot="icon">videocam</md-icon> Videos </md-primary-tab> <md-primary-tab> <md-icon slot="icon">photo</md-icon> Photos </md-primary-tab> <md-primary-tab> <md-icon slot="icon">audiotrack</md-icon> Music </md-primary-tab> </md-tabs> <!-- Tabs with inline icons (like secondary tabs) --> <md-tabs> <md-primary-tab inline-icon> <md-icon slot="icon">flight</md-icon> Flights </md-primary-tab> <md-primary-tab inline-icon> <md-icon slot="icon">hotel</md-icon> Hotels </md-primary-tab> </md-tabs> <!-- Tab panels with accessibility --> <md-tabs aria-label="Content categories"> <md-primary-tab id="videos-tab" aria-controls="videos-panel">Videos</md-primary-tab> <md-primary-tab id="photos-tab" aria-controls="photos-panel">Photos</md-primary-tab> </md-tabs> <div id="videos-panel" role="tabpanel" aria-labelledby="videos-tab"> Video content here... </div> <div id="photos-panel" role="tabpanel" aria-labelledby="photos-tab" hidden> Photo content here... </div> <script> const tabs = document.getElementById('main-tabs'); const panels = document.querySelectorAll('[role="tabpanel"]'); tabs.addEventListener('change', (e) => { const activeIndex = e.target.activeTabIndex; panels.forEach((panel, i) => { panel.hidden = i !== activeIndex; }); }); </script> ``` ## Slider Component Sliders allow users to select a value or range from a track. They can be continuous, discrete with tick marks, or range sliders with two handles. ```html <!-- Continuous slider --> <md-slider min="0" max="100" value="50"></md-slider> <!-- Discrete slider with tick marks --> <md-slider step="10" ticks min="0" max="100" value="50"></md-slider> <!-- Range slider with two handles --> <md-slider range value-start="25" value-end="75"></md-slider> <!-- Labeled slider (shows value on interaction) --> <md-slider labeled min="0" max="100" value="50"></md-slider> <!-- Range slider with labels --> <md-slider range labeled value-start="20" value-end="80"></md-slider> <!-- Custom step size --> <md-slider step="5" ticks min="0" max="50" value="25"></md-slider> <!-- Handle slider changes --> <script> const slider = document.querySelector('md-slider'); slider.addEventListener('input', (e) => { // Fires continuously while dragging console.log('Current value:', e.target.value); }); slider.addEventListener('change', (e) => { // Fires when user releases the handle console.log('Final value:', e.target.value); }); // For range sliders const rangeSlider = document.querySelector('md-slider[range]'); rangeSlider.addEventListener('change', (e) => { console.log('Range:', e.target.valueStart, '-', e.target.valueEnd); }); </script> <!-- Slider in form --> <form> <label> Volume: <span id="volume-display">50</span>% <md-slider name="volume" min="0" max="100" value="50" labeled></md-slider> </label> </form> ``` ## Progress Indicators Progress indicators inform users about the status of ongoing processes. Linear progress shows progress along a track; circular progress shows progress in a ring. ```html <!-- Determinate progress (known completion) --> <md-linear-progress value="0.5"></md-linear-progress> <md-circular-progress value="0.75"></md-circular-progress> <!-- Indeterminate progress (unknown completion time) --> <md-linear-progress indeterminate></md-linear-progress> <md-circular-progress indeterminate></md-circular-progress> <!-- Four-color indeterminate (cycles through colors) --> <md-linear-progress four-color indeterminate></md-linear-progress> <md-circular-progress four-color indeterminate></md-circular-progress> <!-- Linear progress with buffer --> <md-linear-progress value="0.3" buffer="0.6"></md-linear-progress> <!-- Progress with accessibility label --> <md-circular-progress value="0.7" aria-label="Download progress: 70%"> </md-circular-progress> <!-- Dynamic progress update --> <script> const progress = document.querySelector('md-linear-progress'); let currentProgress = 0; async function uploadFile(file) { progress.value = 0; // Simulate upload progress const interval = setInterval(() => { currentProgress += 0.1; progress.value = currentProgress; if (currentProgress >= 1) { clearInterval(interval); console.log('Upload complete!'); } }, 500); } </script> <!-- Loading state pattern --> <div id="content-area"> <md-circular-progress indeterminate id="loader"></md-circular-progress> </div> <script> const loader = document.getElementById('loader'); async function loadContent() { loader.style.display = 'block'; try { const data = await fetch('/api/data'); // Render content... } finally { loader.style.display = 'none'; } } </script> ``` ## Chip Components Chips help users enter information, make selections, filter content, or trigger actions. Four types serve different purposes: assist, filter, input, and suggestion chips. ```html <!-- Chip set container --> <md-chip-set aria-label="Actions"> <!-- Assist chip - for smart actions --> <md-assist-chip label="Add to calendar"> <md-icon slot="icon">event</md-icon> </md-assist-chip> <!-- Filter chip - for filtering content --> <md-filter-chip label="Vegetarian" selected></md-filter-chip> <md-filter-chip label="Vegan"></md-filter-chip> <!-- Input chip - user-entered data --> <md-input-chip label="John Doe" avatar> <img slot="icon" src="avatar.jpg" alt=""> </md-input-chip> <!-- Suggestion chip - dynamic suggestions --> <md-suggestion-chip label="Sounds good!"></md-suggestion-chip> </md-chip-set> <!-- Filter chips for content filtering --> <h3 id="categories-label">Categories</h3> <md-chip-set aria-labelledby="categories-label"> <md-filter-chip label="Electronics" selected></md-filter-chip> <md-filter-chip label="Clothing"></md-filter-chip> <md-filter-chip label="Books"></md-filter-chip> <md-filter-chip label="Home & Garden"></md-filter-chip> </md-chip-set> <script> const filterChips = document.querySelectorAll('md-filter-chip'); filterChips.forEach(chip => { chip.addEventListener('click', () => { chip.selected = !chip.selected; updateFilters(); }); }); </script> <!-- Removable filter chips --> <md-chip-set> <md-filter-chip label="Size: Large" removable selected></md-filter-chip> <md-filter-chip label="Color: Blue" removable selected></md-filter-chip> </md-chip-set> <script> document.querySelectorAll('md-filter-chip[removable]').forEach(chip => { chip.addEventListener('remove', () => { chip.remove(); updateFilters(); }); }); </script> <!-- Input chips for tags/recipients --> <md-outlined-text-field label="Recipients" type="email"></md-outlined-text-field> <md-chip-set> <md-input-chip label="alice@example.com"></md-input-chip> <md-input-chip label="bob@example.com"></md-input-chip> </md-chip-set> <!-- Elevated chips (for use over images) --> <div class="image-overlay"> <md-chip-set> <md-suggestion-chip label="Share" elevated></md-suggestion-chip> <md-suggestion-chip label="Save" elevated></md-suggestion-chip> </md-chip-set> </div> ``` ## Floating Action Button (FAB) FABs represent the most important action on a screen, providing prominent access to key functionality. Available in standard, small, large, and extended variants. ```html <!-- Standard FAB --> <md-fab aria-label="Create new item"> <md-icon slot="icon">add</md-icon> </md-fab> <!-- Extended FAB with label --> <md-fab label="Create"> <md-icon slot="icon">add</md-icon> </md-fab> <!-- Extended FAB without icon --> <md-fab label="Compose"></md-fab> <!-- FAB sizes --> <md-fab size="small" aria-label="Edit"> <md-icon slot="icon">edit</md-icon> </md-fab> <md-fab aria-label="Edit"> <md-icon slot="icon">edit</md-icon> </md-fab> <md-fab size="large" aria-label="Edit"> <md-icon slot="icon">edit</md-icon> </md-fab> <!-- FAB color variants --> <md-fab variant="primary" aria-label="Add"> <md-icon slot="icon">add</md-icon> </md-fab> <md-fab variant="secondary" aria-label="Add"> <md-icon slot="icon">add</md-icon> </md-fab> <md-fab variant="tertiary" aria-label="Add"> <md-icon slot="icon">add</md-icon> </md-fab> <md-fab variant="surface" aria-label="Add"> <md-icon slot="icon">add</md-icon> </md-fab> <!-- Lowered FAB (reduced elevation) --> <md-fab lowered aria-label="Edit"> <md-icon slot="icon">edit</md-icon> </md-fab> <!-- Branded FAB (with custom logo) --> <md-branded-fab aria-label="Add with Google"> <svg slot="icon" viewBox="0 0 36 36"> <path fill="#34A853" d="M16 16v14h4V20z"></path> <path fill="#4285F4" d="M30 16H20l-4 4h14z"></path> <path fill="#FBBC05" d="M6 16v4h10l4-4z"></path> <path fill="#EA4335" d="M20 16V6h-4v14z"></path> </svg> </md-branded-fab> <!-- FAB positioning (typically bottom-right corner) --> <style> md-fab { position: fixed; bottom: 16px; right: 16px; } </style> ``` ## List Component Lists display continuous, vertical indexes of text and images. List items can be interactive (buttons/links) or static text. ```html <!-- Basic list --> <md-list style="max-width: 300px;"> <md-list-item> <div slot="headline">Inbox</div> <div slot="supporting-text">5 unread messages</div> <md-icon slot="start">inbox</md-icon> <span slot="trailing-supporting-text">5</span> </md-list-item> <md-divider></md-divider> <md-list-item> <div slot="headline">Sent</div> <md-icon slot="start">send</md-icon> </md-list-item> <md-list-item> <div slot="headline">Drafts</div> <md-icon slot="start">drafts</md-icon> <span slot="trailing-supporting-text">2</span> </md-list-item> </md-list> <!-- Interactive list items --> <md-list> <md-list-item type="button" onclick="handleSettings()"> <div slot="headline">Settings</div> <md-icon slot="start">settings</md-icon> <md-icon slot="end">chevron_right</md-icon> </md-list-item> <md-list-item type="link" href="/profile" target="_self"> <div slot="headline">View Profile</div> <md-icon slot="start">person</md-icon> </md-list-item> <md-list-item type="link" href="https://help.example.com" target="_blank"> <div slot="headline">Help Center</div> <md-icon slot="start">help</md-icon> <md-icon slot="end">open_in_new</md-icon> </md-list-item> </md-list> <!-- List with images --> <md-list> <md-list-item> <div slot="headline">Vacation Photos</div> <div slot="supporting-text">24 items</div> <img slot="start" src="album-cover.jpg" style="width: 56px"> </md-list-item> </md-list> <!-- Keyboard navigation --> <script> const list = document.querySelector('md-list'); // Programmatic focus management list.activateNextItem(); // Focus next item list.activatePreviousItem(); // Focus previous item </script> ``` ## Icon Component Icons visually represent actions and content. Material Web supports Material Symbols fonts in outlined, rounded, and sharp styles. ```html <!-- Load Material Symbols font --> <link href="https://fonts.googleapis.com/icon?family=Material+Symbols+Outlined" rel="stylesheet"> <!-- Icon by name (ligature) --> <md-icon>settings</md-icon> <md-icon>favorite</md-icon> <md-icon>home</md-icon> <!-- Icon by codepoint --> <md-icon></md-icon> <!-- SVG icon --> <md-icon> <svg viewBox="0 0 24 24"> <path d="M12 2L2 7l10 5 10-5-10-5zM2 17l10 5 10-5M2 12l10 5 10-5"/> </svg> </md-icon> <!-- Different icon styles --> <link href="https://fonts.googleapis.com/icon?family=Material+Symbols+Rounded" rel="stylesheet"> <link href="https://fonts.googleapis.com/icon?family=Material+Symbols+Sharp" rel="stylesheet"> <style> .rounded { --md-icon-font: 'Material Symbols Rounded'; } .sharp { --md-icon-font: 'Material Symbols Sharp'; } </style> <md-icon>home</md-icon> <md-icon class="rounded">home</md-icon> <md-icon class="sharp">home</md-icon> <!-- Filled icons --> <style> md-icon[filled] { font-variation-settings: 'FILL' 1; } </style> <md-icon>favorite</md-icon> <md-icon filled>favorite</md-icon> <!-- Custom size and color --> <style> md-icon { --md-icon-size: 48px; color: #006A6A; } </style> ``` ## Theming with Design Tokens Material Web uses CSS custom properties (design tokens) for comprehensive theming. Tokens cascade from system-level values to component-specific overrides. ```html <!-- Global theme configuration --> <style> :root { /* System color tokens */ --md-sys-color-primary: #6750A4; --md-sys-color-on-primary: #FFFFFF; --md-sys-color-primary-container: #EADDFF; --md-sys-color-secondary: #625B71; --md-sys-color-surface: #FFFBFE; --md-sys-color-surface-container: #F3EDF7; --md-sys-color-on-surface: #1C1B1F; --md-sys-color-outline: #79747E; --md-sys-color-error: #B3261E; /* Typography tokens */ --md-ref-typeface-brand: 'Roboto'; --md-ref-typeface-plain: 'Roboto'; --md-sys-typescale-body-medium-size: 14px; --md-sys-typescale-body-medium-line-height: 20px; /* Shape tokens */ --md-sys-shape-corner-small: 4px; --md-sys-shape-corner-medium: 8px; --md-sys-shape-corner-large: 12px; --md-sys-shape-corner-extra-large: 16px; } </style> <!-- Component-specific tokens --> <style> /* Customize all filled buttons */ md-filled-button { --md-filled-button-container-color: #006A6A; --md-filled-button-label-text-color: #FFFFFF; --md-filled-button-container-shape: 8px; } /* Scoped customization */ .danger-button { --md-filled-button-container-color: var(--md-sys-color-error); } /* Customize text fields */ md-filled-text-field { --md-filled-text-field-container-color: #F5F5F5; --md-filled-text-field-focus-active-indicator-color: #006A6A; } /* Customize checkboxes */ md-checkbox { --md-checkbox-selected-container-color: #006A6A; --md-checkbox-selected-icon-color: #FFFFFF; --md-checkbox-container-shape: 4px; } </style> <!-- Dark theme example --> <style> .dark-theme { --md-sys-color-primary: #D0BCFF; --md-sys-color-on-primary: #381E72; --md-sys-color-surface: #1C1B1F; --md-sys-color-on-surface: #E6E1E5; --md-sys-color-surface-container: #211F26; color-scheme: dark; } </style> <body class="dark-theme"> <md-filled-button>Dark theme button</md-filled-button> </body> ``` ## Summary Material Web provides a production-ready implementation of Material Design 3 for the web platform. The library excels in scenarios requiring consistent, branded UI components that work across frameworks and provide excellent accessibility out of the box. Its design token system enables sophisticated theming from global brand colors down to individual component customization, making it suitable for enterprise applications, design systems, and any project prioritizing Material Design's visual language. Key integration patterns include importing only needed components to minimize bundle size, leveraging CSS custom properties for theming at various scopes, and using the native form participation APIs for seamless integration with HTML forms. Components work with any framework (React, Vue, Angular, Svelte) or vanilla JavaScript. For complex applications, consider combining Material Web with state management libraries while relying on its built-in accessibility features for keyboard navigation, screen reader support, and ARIA compliance.