# Material 3 component guidelines for LLMs This file is the **design contract** for generating UI with ExpressiveCSS. ExpressiveCSS implements [Material Design 3](https://m3.material.io/) (including the 2025 **M3 Expressive** updates) on the web. Read this file to decide *which* component to use, *how* it is structured, *where* it sits, and *how* it adapts. Read [`llm.md`](llm.md) for markup, class names, tokens, and JavaScript APIs. Canonical source: [m3.material.io](https://m3.material.io/). Where this file and the live spec disagree, the spec wins for design intent; [`llm.md`](llm.md) wins for what this framework actually ships. --- ## How to use this file 1. Pick a **window size class** for the layout you are generating. Adaptive rules below are load-bearing, not optional polish. 2. Use the **component chooser** to pick one component per job. Do not stack two components that do the same job (navigation bar + rail, dialog + snackbar for the same event, FAB + filled button for the same action). 3. Open the matching **component** section for anatomy, placement, behavior, and the ExpressiveCSS mapping. 4. Emit the **documented HTML**. Do not invent retired class names (`navbar`, `nav-wrapper`, `brand-logo`, `btn`, `card-content`, `modal-header`, `lever`, `filled-in`, `with-gap`). 5. If a Material 3 component is listed under **Not shipped**, do not fake it with a look-alike. Use the documented substitute, or say it is not available. --- ## Hard rules These are the mistakes generated Material UIs make most often. Treat them as invariants. - **One high-emphasis action per region.** A screen may have many buttons. Only one should be filled, a FAB, or an extended FAB. - **Sentence case** on buttons, chips, tabs, and snackbar actions. Capitalize the first word and proper nouns only. Never `SAVE`, `Save Changes`, or `OK`. - **Material target recommendation:** aim for a 48×48 dp interaction area even when the glyph is smaller. Measure the web hit area in CSS pixels and check the selected component contract. This design recommendation is distinct from [WCAG 2.2 AA SC 2.5.8](https://www.w3.org/WAI/WCAG22/Understanding/target-size-minimum.html), which requires 24×24 CSS pixels or a documented spacing, equivalent-control, inline, user-agent-control, or essential exception. CSS pixels are independent of device pixel ratio. - **Color roles, never hex.** Use `primary`, `on-surface`, `error`, and the other `--md-sys-color-*` roles. Do not hard-code `#6750A4`. - **Native HTML first.** ` ``` From script, `Expressive.Theme.set('dark')` does the same as a click, `Expressive.Theme.get()` returns the current theme (`auto` without an attribute), and `Expressive.Theme.sync(root)` marks theme controls rendered after load. The behavior never restores a saved choice on load, because the bundle runs after first paint; keep the inline snippet for that. ### Creating a theme Customize by overriding the Material Design 3 tokens. Do not set `--background-color`, `--primary-color`, or other pre-2.1 names — those are not wired in Expressive. Three layers exist. `tokens/_reference.scss` generates the tonal ramps from `--md-source`, then resolves them into the pairs (`--md-sys-color-primary-light`, `--md-sys-color-primary-dark`, and the rest). `tokens/_theme.scss` collapses each pair into the live `--md-sys-color-*` name with `light-dark()`. Components only read the live names. Override the `-light` and `-dark` pairs so both schemes stay consistent. Load your sheet **after** Expressive so equal-specificity `:root` rules win. ```css :root { --md-sys-color-primary-light: #6750a4; --md-sys-color-on-primary-light: #ffffff; --md-sys-color-primary-container-light: #eaddff; --md-sys-color-on-primary-container-light: #21005d; --md-sys-color-primary-dark: #d0bcff; --md-sys-color-on-primary-dark: #381e72; --md-sys-color-primary-container-dark: #4f378b; --md-sys-color-on-primary-container-dark: #eaddff; } ``` To restyle only one scheme, set the live names on the attribute selector. A bare `:root { --md-sys-color-primary: … }` loses to `:root[theme='dark']` because the attribute rule is more specific. ```css :root[theme='dark'] { --md-sys-color-primary: #d0bcff; --md-sys-color-on-primary: #381e72; --md-sys-color-surface: #1c1b1f; --md-sys-color-on-surface: #e6e1e5; } ``` The same custom properties inherit, so a wrapper can preview a palette without touching the rest of the page: ```html
Filled
``` In Sass, consume the live token. The values are hex, so `rgba(var(--md-sys-color-primary), 0.06)` is invalid and the browser drops it. Mix with transparency instead: ```css .my-surface { background-color: var(--md-sys-color-surface); color: var(--md-sys-color-on-surface); } .my-overlay { background-color: color-mix(in oklab, var(--md-sys-color-primary) 6%, transparent); } ``` `--md-source` is the seed the ramps are generated from, and it is live: set it and every generated ramp — and every system color that resolves to one — recolors at runtime, with no rebuild. Expressive ships `#c6a0f6`, Mist Iris. ```css :root { --md-source: #6750a4; /* one line; the whole theme follows */ } ``` Five of the six ramps are derived this way with `oklch(from var(--md-source) …)`. The **error** ramp is deliberately not: Material fixes the error hue rather than deriving it, because "this went wrong" should not change color when you change your brand color. Overriding an individual `-light`/`-dark` pair still works and still wins — that is the more surgical tool. `--md-source` is the blunt one. Where the shipped seed `#c6a0f6` lands, for the roles you will most often replace. These are *resolved* values: the stylesheet ships the `oklch()` expression, and the browser computes the color — including gamut-mapping the entries whose target chroma sRGB cannot reach — so treat them as accurate to about a rounding step rather than as literals to paste back in. | Token | Light | Dark | | --- | --- | --- | | `primary` | #6e4995 | #d8b2ff | | `on-primary` | #ffffff | #3f1861 | | `primary-container` | #f5ceff | #56307a | | `on-primary-container` | #2a0048 | #f5ceff | | `secondary` | #635a6b | #ccc1d5 | | `secondary-container` | #e8ddf2 | #4b4253 | | `tertiary` | #7a5059 | #e8b7c0 | | `error` | #ba1a1a | #ffb4ab | | `surface` | #faf8fb | #090809 | | `on-surface` | #1c1b1d | #e3e1e4 | | `outline` | #7a757c | #938e96 | `error` is the one row that does not move when you change the seed — it is the ramp that is not generated. The full list of role utilities lives on the Color page. Pair a fill with its `on-*` text class so contrast stays correct when the scheme flips. ### Vibrant emphasis `vibrant` is Material 3 Expressive's emphasis axis, and it is a foundation rather than a component variant: the attribute remaps the surface family of `--md-sys-color-*` roles inside its subtree onto the tertiary container, and every component already reads those roles. Nothing is restyled until you write the attribute. ```html
…
``` The remap covers `surface`, all five `surface-container` rungs, `surface-dim`, `surface-bright`, and their `on-*` roles. Accent roles are untouched, so a filled button still stands out; outline roles are untouched too, because M3's outline is neutral-variant rather than an opacity of the text color, and deriving it would turn every checkbox, radio and switch border in the subtree translucent. It points at the live role names, so a runtime theme switch reaches it. There is one ramp, tertiary — M3's for this axis. Pointing the surfaces at primary or secondary would erase every component whose own fill is that container: a tonal button, a FAB, `.toolbar.vibrant`. Set the surface tokens on your own wrapper if you want a different one. The elevation ladder collapses — every `surface-container` rung resolves to the one container color, which is what a vibrant surface is in Material, and `on-surface-variant` collapses onto `on-surface` for the same reason — so put the attribute on the component you want emphasized, not on the page. Menus and toolbars also carry a `.vibrant` class; those are Material's own per-component token sets, and the attribute is the general axis. A menu inside a vibrant subtree adopts its vibrant mapping automatically — a selected item is filled with `tertiary-container`, the colour the attribute paints the menu with, so M3 moves selection to solid `tertiary`. `:host([vibrant])` is matched alongside `[vibrant]`, so a shadow-DOM host can carry it. ### More contrast Material 3 has three contrast levels. Put `contrast="medium"` or `contrast="high"` on the root or on any subtree to use the medium or high scheme there. The accent roles, their containers, `on-surface-variant` and the outlines move to darker tones in the light scheme and lighter ones in the dark scheme, taken from the same ramps, so a runtime `--md-source` change still reaches them. Surfaces stay put. Medium brings accents to about 4.5:1 against the surface and high to 7:1, with outlines at 3:1 or more. When the user asks for more contrast (`prefers-contrast: more`), the page uses the high scheme unless a `contrast` attribute says otherwise; `contrast="standard"` opts a page or subtree out. The tones approximate Material's contrast curves rather than reproducing its color solver. A page that re-themes through the `-light` and `-dark` pairs should repeat those overrides inside its own `[contrast]` rule. ```html ``` ### Corner scale Component shape tokens on the Material 3 corner scale read the `md.sys.shape.corner` tokens, so one override changes the corners of every component on that step. A component token such as `--md-comp-card-container-shape` still overrides one component. Off-scale corners stay literal. | Token | Value | | --- | --- | | `--md-sys-shape-corner-none` | 0px | | `--md-sys-shape-corner-extra-small` | 4px | | `--md-sys-shape-corner-small` | 8px | | `--md-sys-shape-corner-medium` | 12px | | `--md-sys-shape-corner-large` | 16px | | `--md-sys-shape-corner-large-increased` | 20px | | `--md-sys-shape-corner-extra-large` | 28px | | `--md-sys-shape-corner-extra-large-increased` | 32px | | `--md-sys-shape-corner-extra-extra-large` | 48px | | `--md-sys-shape-corner-full` | 9999px | ```css :root { --md-sys-shape-corner-medium: 8px; } /* cards, menu items and other medium corners */ ``` #### Cut corners Material shapes come in a rounded and a cut family. `corners="cut"` on the root or on any subtree turns the corners of cards, dialogs, sheets, menus, fieldsets, buttons, chips, alerts, snackbars, tooltips, popovers and outlined fields into straight bevels of the same size; `corners="round"` puts a subtree back. The switch sets `--md-sys-shape-corner-family` to `bevel` or `round`. `.corner-cut` cuts a single element, together with its own radius or a `.corner-*` class. Round indicators such as radios, switches, avatars and `.circle` stay round, because a cut 50% radius is a diamond. Cut corners use CSS `corner-shape`. Browsers without it, including Firefox 157, keep rounded corners. ```html
…
One cut panel
``` --- ## Design tokens Every token family in one place: color, type, state, motion, shape, elevation and stacking. Every design decision the framework makes is a CSS custom property you can override at runtime, with no rebuild. The system tokens follow Material 3 names (`--md-sys-*` and `--md-ref-*`); components read them through their own `--md-comp-*` tokens, which change one component at a time. | Family | Prefix | What it holds | Details | | --- | --- | --- | --- | | Color roles | `--md-sys-color-*` | `primary`, `on-surface`, `outline-variant`: 45 roles, each with a `-light` and `-dark` pair | [Color](https://www.expressivecss.com/color.html) | | Tonal palettes | `--md-ref-palette-*` | Tones 0 to 100 of the primary, secondary, tertiary, neutral, neutral-variant and error ramps, generated from `--md-source` | [Themes](https://www.expressivecss.com/themes.html) | | Contrast levels | `contrast="medium" | "high"` | An attribute, not a token: moves accents, outlines and `on-surface-variant` to higher-contrast tones | [Themes](https://www.expressivecss.com/themes.html#contrast) | | Type scale | `--md-sys-typescale-*` | Font, size, weight, line height and tracking for the fifteen roles, and `--md-ref-typeface-*` | [Typography](https://www.expressivecss.com/typography.html) | | State layers | `--md-sys-state-*` | Hover, focus, pressed and dragged opacities | [State layers](https://www.expressivecss.com/state-layers.html) | | Motion | `--md-sys-motion-*` | Seven easing curves and sixteen durations, `short1` to `extra-long4` | [Transitions](https://www.expressivecss.com/css-transitions.html#motion-tokens) | | Shape | `--md-sys-shape-corner-*` | The corner scale from `none` to `full` | [Shapes](https://www.expressivecss.com/shapes.html#corner-scale) | | Elevation | `--md-sys-elevation-level*` | Shadows for levels 0 to 5 and 1-half | [Elevation](https://www.expressivecss.com/shadow.html) | | Stacking | `--expressive-z-*` | The z-index order of fixed and floating surfaces | [Elevation](https://www.expressivecss.com/shadow.html#stacking) | Set a system token on `:root` to change every component, or on any element to change only what is inside it. Each token is declared on `:root` and `:host`, so the same overrides work when the stylesheet is adopted by a shadow root. ```css :root { --md-source: #006495; /* re-themes every color role */ --md-sys-shape-corner-medium: 8px; /* squarer cards and menus */ --md-sys-motion-duration-short4: 150ms; /* faster 200ms transitions */ } .dense-panel { --md-sys-elevation-level1: none; } .my-card { --md-comp-card-container-shape: 0; } /* one component */ ``` --- ## Color One system: the Material Design 3 theme tokens. Color in Expressive is the Material Design 3 Expressive roles — CSS custom properties on `:root` named `--md-sys-color-*`, exposed as utility classes like `.primary` and `.on-surface-text`. There are 26 standard roles in six groups (primary, secondary, tertiary, error, surface, outline), plus optional add-ons for fixed accents and the surface container scale. The 2014 Material palette that shipped with earlier versions (`.red`, `.blue.lighten-2`, `colorFunc()`) has been removed. It generated 532 utility classes — 18% of the stylesheet — expressing a design opinion this framework does not hold, and it did not follow the page theme. Replace a palette class with the role it was standing in for: `.red` → `.error`, `.blue` → `.primary`, `.green` → `.tertiary`, and pair each fill with its `on-*` text class. Token values follow the page theme. The docs site sets `` or `theme="dark"`. Without that attribute, the tokens follow `prefers-color-scheme`. A background class sets `background-color`. Append `-text` for `color`. Pair roles as the spec intends so contrast stays at least 3:1: primary for the FAB and filled buttons, secondary for filter chips and selected nav pills, tertiary for contrasting accents, error for error states, surface for page backgrounds, surface-container* for cards/sheets/dialogs/menus. `on-*` is text and icons on that fill. Container roles are fills, not text. ```html
.primary
.on-surface-text ``` Every role name is a background class. The same name plus `-text` is the foreground class (`.on-surface-text`). Prefer the `on-*` text class on its paired fill. Standard pairs: `primary` / `on-primary`, `primary-container` / `on-primary-container`, and the same for secondary, tertiary, and error. Surface: `surface`, `surface-dim`, `surface-bright`, `surface-container-lowest` … `surface-container-highest`, `on-surface`, `on-surface-variant`. Outline: `outline`, `outline-variant`. Inverse: `inverse-surface` / `inverse-on-surface`, `inverse-primary`. Overlay: `scrim`, `shadow`. Optional fixed accents (`primary-fixed`, `primary-fixed-dim`, `on-primary-fixed`, `on-primary-fixed-variant`, and the secondary/tertiary copies) stay the same in light and dark. `background`, `on-background`, `surface-variant`, and `surface-tint` remain as aliases. `scrim` is the opaque neutral the wash behind a modal surface is mixed from, not the wash itself. That is `--md-comp-scrim-color` — the role at 32%, defined once on `:root, :host` (so a sheet adopted into a shadow root gets one too) and consumed by dialogs, both sheets, and the modal navigation rail. Override it at the root to retheme all of them, or set it on one element to dim just that surface (`::backdrop` inherits from the element it belongs to). The mix resolves at the root, so overriding `--md-sys-color-scrim` on a subtree does not reach a scrim below it — override `--md-comp-scrim-color` there instead. In Sass, consume the token directly. Do not write `rgba(var(--md-sys-color-primary), 0.06)` — the tokens hold hex colors, so that form is invalid. Mix with transparency instead: ```css .my-tint { background-color: var(--md-sys-color-primary); color: var(--md-sys-color-on-primary); } .my-overlay { background-color: color-mix(in oklab, var(--md-sys-color-primary) 6%, transparent); } ``` Mix `in oklab`, not `in srgb`. sRGB interpolation dips in lightness through the midtones, so the same percentage reads muddier on some hues than others; OKLab is perceptually uniform, so a 16% state layer looks like 16% everywhere. ### Every role A role is a job, not a color: `error` means "this went wrong", and what that looks like is the theme's business. ### Sass Do not `@extend` these classes across files — that is how the old stylesheet lost control of cascade order. In a component partial, read the token directly. ```css .my-panel { background-color: var(--md-sys-color-surface-container); color: var(--md-sys-color-on-surface); } ``` There is no Sass color function any more. `colorFunc()` and the `$colors` map were removed with the palette — a Sass function resolves at build time, which cannot follow a theme the user switches at runtime. The custom property can. --- ## Grid Use Expressive's CSS Grid system to format a page in an ordered, comfortable way. We are using a standard 12 column fluid responsive grid system. The grid helps you layout your page in an ordered, easy fashion. ### Container The container class is not strictly part of the grid but is important in laying out content. It allows you to center your page content. The `container` class is set to ~70% of the window width. It helps you center and contain your page content. We use the container to contain our body content. #### Demo Try the button below to see what the page looks like without containers. To add a container just put your content inside a `
` tag with a `container` class. Here's an example of how your page might be set up. ```html
``` ### Introduction Take a look at this section to quickly understand how the grid works! #### 12 Columns Our standard grid has 12 columns. No matter the size of the browser, each of these columns will always have an equal width. To get a feel of how the grid is used in HTML, take a look at the code below which will produce a similar result to the one above. ```html
1
2
3
4
5
6
7
8
9
10
11
12
``` `s1` means one column at the Compact/default size and up. #### Columns live inside Rows Remember when you are creating your layout that all columns must be contained inside a row. Size each inner div with a screen-prefix class such as `s12` or `m6`. ```html
This div is 12-columns wide on all screen sizes
6-columns (one-half)
6-columns (one-half)
``` ### Offsets To offset, simply add `offset-s2` to the class where the prefix identifies the window size (`s` = Compact, `m` = Medium, `l` = Expanded, `xl` = Large, `xxl` = Extra-large) and the number is how many columns to offset. Attention! Offsets are calculated absolutely starting from the left. If you need relative offsets, add empty columns to the row. ```html
This div is 12-columns wide on all screen sizes
6-columns (offset-by-6)
l6 column
l4 column (offset-l8)
offset-l3
offset-l6
offset-l9
col
relative offset 2
``` ### Gaps There is a default gap between the columns (g-3). You can easily change the gap with the gap classes. Simply add `g-0` to `g-5` to the element with the `row` class. ```html
1
2
3
``` ### Push and pull Deprecated. CSS Grid is used now — use offsets, or empty columns, to change placement. Older versions reordered columns with `push-s2` or `pull-s2`, where `s` is the screen class-prefix and the number is how many columns to push or pull by. Those classes are no longer part of the grid. ### Creating layouts Here we will show you how to create some commonly used layouts with our grid system. Hopefully these will get you more comfortable with laying out elements. To keep these demos simple, the ones here will not be responsive. #### Section The section class is used for simple top and bottom padding. Just add the `section` class to your divs containing large blocks of content. #### Divider Dividers are 1 pixel lines that help break up your content. Just add the `divider` class to a div in between your content. #### Example Sections and Dividers ```html
Section 1

Stuff

Section 2

Stuff

Section 3

Stuff

``` #### Example Promotion Table If we want 3 divs that are equal size, we define the divs with a width of 4-columns, as 4+4+4 nicely adds up to 12. Inside those divs, we can put our content. ```html
``` #### Example Side Navigation Layout You can see how easy it is to create layouts using the grid system. Just remember to make sure your column numbers add up to 12 for an even layout. ```html
``` ### Creating responsive layouts Above we showed you how to layout elements using our grid system. Now we'll show you how to design your layouts so that they look great on all screen sizes. #### Screen Sizes | | Compact `< 600px` | Medium `600–839px` | Expanded `840–1199px` | Large `1200–1599px` | Extra-large `>= 1600px` | | --- | --- | --- | --- | --- | --- | | **Class Prefix** | `.s` | `.m` | `.l` | `.xl` | `.xxl` | | **Container Width** | 90% | 85% | 70% | 70% | 75% | | **Number of Columns** | 12 | 12 | 12 | 12 | 12 | #### Adding Responsiveness In the previous examples, we only defined the Compact/default size using `s12`. This is fine if we want a fixed layout since the rules propagate upwards. By just saying `s12`, we are essentially saying `s12 m12 l12 xl12 xxl12`. Define later prefixes when the layout should change at wider window size classes. ```html
I am always full-width (s12)
I am full-width on mobile (s12 m6)
``` #### Responsive Side Navigation Layout In this example below, we take the same layout from above, but we make it responsive by defining how many columns the div should take up on each screen size. Try resizing your browser and watch the layout change below. ```html
``` #### More Responsive Grid Examples ```html
s12
s12 m4 l2
s12 m4 l8
s12 m4 l2
s12 m6 l3
s12 m6 l3
s12 m6 l3
s12 m6 l3
``` --- ## Helpers An overview of the helper classes for alignment, visibility, spacing, and common CSS properties. ### Alignment Easy-to-use classes to help you align your content. #### Vertical Align You can easily vertically center things by adding the class `valign-wrapper` to the container holding the items you want to vertically align. ```html
This should be vertically aligned
``` #### Text Align These classes are for horizontally aligning content: `.left-align`, `.right-align` and `.center-align`. Use `.start-align` and `.end-align` to follow the text direction with `text-align: start` and `text-align: end`. The physical left and right classes keep their existing behavior. ```html
This should be left aligned
This should be right aligned
This should be center aligned
``` To center text on mobile only, add `center-on-small-only`. ### Display and position | Class | Declaration | | --- | --- | | `.block`, `.inline-block` | `display: block`, `display: inline-block` | | `.grid`, `.inline-grid` | `display: grid`, `display: inline-grid` | | `.grid-auto-fill` | A grid with as many columns as fit, each at least `--grid-column-min` wide (240px by default) | | `.contents` | `display: contents`; the element's box goes away and its children join the parent's layout | | `.relative` | `position: relative` | | `.sticky-top` | `position: sticky; top: 0` | | `.position-absolute`, `.position-fixed`, `.position-static` | `position: absolute`, `position: fixed`, `position: static` | | `.inset-0` | `inset: 0`; the element covers its containing block | | `.top-0`, `.bottom-0` | `top: 0`, `bottom: 0` | | `.start-0`, `.end-0` | `inset-inline-start: 0`, `inset-inline-end: 0`; they swap sides in RTL | | `.query-container` | `container-type: inline-size`. Horizontal cards and description lists inside it stack when it is narrower than 600px, on any window. | `.inline` is the row of checkboxes or radios, so there is no `display: inline` class. A `.sticky-top` element sticks inside its nearest scrolling ancestor; an ancestor with `overflow: hidden` stops it. Give the parent of an absolute element `.relative`. There is no bare `.fixed` class, because the navigation bar, toolbar and table of contents use `.fixed` as a modifier. `.position-fixed` sets no `z-index`; to lift a fixed element above framework surfaces, give it a `--expressive-z-*` value. An ancestor with a `transform`, `filter` or `contain` becomes the containing block of a fixed element. No position class has a window-size prefix, and `.position-static` undoes `.relative` and `.sticky-top`. Browsers have dropped the semantics of elements with `display: contents`, so put `.contents` on plain wrappers, not on buttons, lists, tables or headings. A `.query-container` can no longer size itself from its content, so put it on a wrapper that fills its parent, such as a sidebar column, not on an inline or shrink-to-fit box. `.grid-auto-fill` is `repeat(auto-fill, minmax(min(100%, var(--grid-column-min, 15rem)), 1fr))`. It adds a column whenever another one of the minimum width fits, and the columns share what is left. Set `--grid-column-min` on the grid or on an ancestor. The last row keeps the same column width when it has fewer items. A container narrower than the minimum gets one column as wide as itself. The class sets no gap, so pair it with `.gap-*`, and it has no window-size prefixes, because the column count already follows the container's width. ```html
…
…
…
``` ### Flex One class per declaration, applied to the container. Row direction and start alignment are the flex defaults, but `.flex-row` and `.flex-nowrap` exist so a window-size prefix can switch back to them. | Class | Declaration | | --- | --- | | `.flex` | `display: flex` | | `.inline-flex` | `display: inline-flex` | | `.flex-row`, `.flex-column` | `flex-direction` | | `.flex-wrap`, `.flex-nowrap` | `flex-wrap` | | `.justify-start`, `.justify-center`, `.justify-end`, `.justify-between`, `.justify-around`, `.justify-evenly` | `justify-content` | | `.align-start`, `.align-center`, `.align-end`, `.align-stretch`, `.align-baseline` | `align-items` | | `.flex-1` | `flex: 1 1 0` on a child, so it takes the remaining space | | `.flex-none` | `flex: none` on a child, so it keeps its content size | | `.flex-initial` | `flex: 0 1 auto` on a child, so it sizes from its content, can shrink and does not grow | | `.shrink-0` | `flex-shrink: 0` on a child, so it never gets narrower than its basis | | `.shrink-1` | `flex-shrink: 1` on a child, restoring shrinking while keeping its grow factor and basis | | `.self-start`, `.self-center`, `.self-end`, `.self-stretch` | `align-self` on a child | | `.self-auto` | `align-self: auto` on a child, so it follows the parent's `align-*` again | | `.order-first`, `.order-last`, `.order-none` | `order: -1`, `order: 1`, `order: 0` on a child. `.order-none` puts a child back in its source position, so a prefixed one undoes the other two from that size class up. Visual order only: keyboard and screen reader order still follow the source. | | `.gap-0` to `.gap-6` | `gap` on the spacing scale, `!important`; also works on grid containers | | `.gap-x-0` to `.gap-x-6` | `column-gap` only, `!important` | | `.gap-y-0` to `.gap-y-6` | `row-gap` only, `!important` | ```html

Members

Design Research
``` `justify-*` and `align-*` use `flex-start` and `flex-end`, so they follow the writing direction and mirror in RTL. Components that already lay out their children (app bars, toolbars, card `.actions`, button groups) do not need these classes. The gap scale is `0`, `0.25rem`, `0.5rem`, `0.75rem`, `1rem`, `1.5rem` and `3rem`. `.gap-x-*` and `.gap-y-*` keep the native meanings of `column-gap` and `row-gap` in grid and flex layouts, including RTL and column-direction flex. There are no `auto` gap values. The grid's `.g-*` classes use a separate scale. ```html
Monday
Tuesday
Wednesday
Thursday
Friday
Saturday
``` Both gaps start at `1rem`. From 600px, the column gap becomes `0.5rem` while the row gap stays `1rem`. At the same breakpoint, an axis class overrides `.gap-*` regardless of HTML class order. A later breakpoint's `.gap-*` resets both axes; a later axis class changes only its axis. Use `0` to remove a gap. Avoid conflicting values from the same family at the same breakpoint. ### Window-size prefixes The display, flex direction, wrap, `.flex-1`, `.flex-none`, `.flex-initial`, `.shrink-0`, `.shrink-1`, `justify-*`, `align-*`, `self-*`, `.order-*`, text alignment (`.start-align`, `.center-align`, `.end-align`), `.line-clamp-*`, `.gap-*`, `.gap-x-*`, `.gap-y-*`, margin and padding classes, and `.hide`, also come with a window-size prefix. Prefixed margin and padding cover all sides, `x`, `y`, top, bottom, start and end; use start and end rather than left and right. A prefixed class applies from that size class up and overrides the unprefixed one, the same way the grid's `m6` and `l4` do. `self-center expanded:self-auto` centers a child until Expanded and then follows the parent's `align-*`. | Prefix | Applies from | | --- | --- | | `medium:` | Medium, 600px | | `expanded:` | Expanded, 840px | | `large:` | Large, 1200px | | `extra-large:` | Extra-large, 1600px | ```html

Members

``` A child can change its share of the space too. This filename sizes from its content below Expanded and takes the remaining space from 840px up. The link keeps its size. `.min-w-0` lets the text shrink below its content minimum so it can truncate. Use `.min-h-0` for a child that must shrink inside a bounded column. ```html
Quarterly report with a long filename.pdf Sizing guide
``` A prefixed `flex-*` shorthand sets grow, shrink and basis together, so `shrink-0 medium:flex-initial` allows shrinking from 600px up. Use `shrink-0 medium:shrink-1` to restore shrinking while keeping grow and basis. These resets assign explicit values; they do not recover an earlier component rule. Larger active prefixes win regardless of class order. Self-alignment, ordering and the other sizing helpers have no window-size prefixes. In a Sass selector, escape the colon: `.expanded\:flex-row`. `.medium:hide` hides from Medium up. To show something only from a size up, use the hide-on classes; they are `!important`, so a prefixed display class does not undo them. ### Sizing and overflow Flex and grid children can retain a minimum size based on their content. Clear that minimum when a child needs to shrink, truncate, or scroll. | Class | Declaration | | --- | --- | | `.min-w-0` | `min-width: 0` | | `.min-h-0` | `min-height: 0` | | `.w-full`, `.h-full` | `width: 100%`, `height: 100%` | | `.max-w-full` | `max-width: 100%` | | `.aspect-1x1`, `.aspect-4x3`, `.aspect-16x9` | `aspect-ratio`; the height follows the width | | `.object-cover`, `.object-contain` | `object-fit` on an `` or `