Alignment
Use these classes to align content.
Vertical align
To center items vertically, add the class
valign-wrapper to their container.
This should be vertically aligned
<div class="valign-wrapper">
<h5>This should be vertically aligned</h5>
</div>
Text align
Add .left-align, .right-align or .center-align
to align content horizontally. Use .start-align and .end-align to follow the
text direction. The left and right classes stay physical and do not mirror in RTL.
This should be left aligned
This should be right aligned
This should be center aligned
<div>
<h5 class="left-align">This should be left aligned</h5>
</div>
<div>
<h5 class="right-align">This should be right aligned</h5>
</div>
<div>
<h5 class="center-align">This should be center aligned</h5>
</div>
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. |
There is no display: inline class, because .inline is the row
of checkboxes or radios. A .sticky-top element sticks inside its nearest
scrolling ancestor. An ancestor with overflow: hidden stops it.
An absolute element is placed against its nearest positioned ancestor, so give the
parent .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 value from the
--expressive-z-* scale in Stacking order. An
ancestor with a transform, filter or
contain becomes the containing block of a fixed element, so it stops
covering the viewport. Pad the content on the pinned side, as .pe-6 does below, so text does not run under the pinned element. No position class has a window-size prefix, and
.position-static undoes .relative and .sticky-top.
<article class="relative">
<p class="pe-6">Your storage is almost full. Delete old backups to keep syncing.</p>
<button class="icon-button position-absolute top-0 end-0" type="button" aria-label="Dismiss">
<span class="material-symbols" aria-hidden="true">close</span>
</button>
</article>
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. Put it on
a wrapper that fills its parent, such as a sidebar column, not on an inline or
shrink-to-fit box.
<div class="grid-auto-fill gap-3" style="--grid-column-min: 10rem">
<article class="outlined">…</article>
<article class="outlined">…</article>
<article class="outlined">…</article>
</div>
.grid-auto-fill 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-*. It has no window-size prefixes,
because the column count already follows the container's width.
Flex
Each class sets one declaration, usually on 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. This changes the visual order only. Keyboard and screen reader order still follow the source. |
.gap-0 to .gap-6 | gap on the spacing scale, with !important. Also works on grid containers. |
.gap-x-0 to .gap-x-6 | column-gap only, with !important. |
.gap-y-0 to .gap-y-6 | row-gap only, with !important. |
Members
<div class="flex align-center justify-between gap-3">
<h2 class="title-medium my-0">Members</h2>
<button class="tonal">Invite</button>
</div>
<div class="flex flex-wrap gap-2">
<span class="chip">Design</span>
<span class="chip">Research</span>
</div>
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.
Independent gaps
The gap scale is 0, 0.25rem, 0.5rem,
0.75rem, 1rem, 1.5rem and 3rem.
Use .gap-x-* for column gaps and .gap-y-* for row gaps
on grid or flex containers. They keep the native meanings of column-gap
and row-gap, including in RTL and column-direction flex layouts.
There are no auto gap values. The grid's .g-* classes are a separate scale.
<div class="grid-auto-fill gap-4 medium:gap-x-2" style="--grid-column-min: 8rem">
<div class="surface-container p-3">Monday</div>
<div class="surface-container p-3">Tuesday</div>
<div class="surface-container p-3">Wednesday</div>
<div class="surface-container p-3">Thursday</div>
<div class="surface-container p-3">Friday</div>
<div class="surface-container p-3">Saturday</div>
</div>
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 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
These classes also come with a window-size prefix: display, flex direction, wrap,
.flex-1, .flex-none, .flex-initial,
.shrink-0, .shrink-1,
justify-*, align-*, self-*, text alignment (.start-align,
.center-align, .end-align), .line-clamp-*,
.order-*, .gap-*, .gap-x-*, .gap-y-*, margin, padding and .hide. Prefixed margin and padding cover all sides,
x, y, top, bottom, start and end. Use start and end, not 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.
| Prefix | Applies from |
|---|---|
medium: | Medium, 600px |
expanded: | Expanded, 840px |
large: | Large, 1200px |
extra-large: | Extra-large, 1600px |
<!-- Stacked on Compact and Medium, one row from Expanded up. -->
<div class="flex flex-column gap-2 expanded:flex-row expanded:align-center expanded:justify-between">
<h2 class="title-medium my-0">Members</h2>
<button class="tonal">Invite</button>
</div>
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.
<div class="flex align-center gap-3">
<span class="flex-initial expanded:flex-1 min-w-0 truncate">Quarterly report with a long filename.pdf</span>
<a class="button tonal flex-none" href="#overflow">Sizing guide</a>
</div>
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 <img> or <video> with a set ratio |
.overflow-x-auto | overflow-x: auto |
.overflow-y-auto | overflow-y: auto |
.overflow-hidden | overflow: hidden |
<div class="flex gap-2" style="max-width: 24rem">
<span class="flex-1 min-w-0 truncate">A long filename that must fit beside its action.pdf</span>
<button type="button" class="flex-none">Download</button>
</div>
<section class="flex flex-column" style="height: 12rem" aria-labelledby="activity-title">
<h2 id="activity-title" class="title-medium flex-none">Activity</h2>
<div class="flex-1 min-h-0 overflow-y-auto p-2" tabindex="0" role="region" aria-label="Recent activity">
<p>09:00 Report uploaded.</p>
<p>09:15 Review requested.</p>
<p>09:30 Comments received.</p>
<p>09:45 Changes approved.</p>
</div>
</section>
Scrolling needs a bounded size. Use .overflow-x-auto for wide
tables or action rows. Give a generic scroll region tabindex="0"
and an accessible name when keyboard users cannot otherwise focus and scroll it.
Leave padding for child focus rings, such as .p-2.
.overflow-hidden clips content and focus rings, so use it only
when you mean to hide the clipped content.
Use scroll area for a native scroll container with themed scrollbars.
Borders and corners
| Class | Declaration |
|---|---|
.bordered | A 1px outline-variant border on every side |
.border-top, .border-bottom | The same border on one side |
.border-start, .border-end | The same border on the inline start or end, which mirrors in RTL |
.corner-none, .corner-extra-small, .corner-small, .corner-medium, .corner-large, .corner-extra-large, .corner-full | border-radius from the matching --md-sys-shape-corner-* token |
.corner-cut | corner-shape: bevel. The element's corners become straight cuts of the same size. Browsers without corner-shape round them instead. |
<div class="bordered corner-large aspect-16x9">16:9</div>
<img class="corner-medium aspect-1x1 object-cover" src="..." alt="..." width="160">
These classes use other names because .border is the outlined card variant
and .rounded is the pill button. On a component, a corner class replaces the
component's own shape, including its pressed and selected corner changes.
Hiding and showing content
These classes hide or show content at specific screen sizes.
| Class | Screen range |
|---|---|
.hide |
Hidden on all devices |
.hide-on-compact-only |
Hidden on Compact (< 600px) |
.hide-on-med-and-down |
Hidden on Compact and Medium (< 840px) |
.hide-on-med-and-up |
Hidden on Medium and wider (≥ 600px) |
.hide-on-medium-only |
Hidden on Medium (600 to 839px) |
.hide-on-expanded-only |
Hidden on Expanded (840 to 1199px) |
.hide-on-expanded-and-up |
Hidden on Expanded and wider (≥ 840px) |
.hide-on-large-only |
Hidden on Large (1200 to 1599px) |
.hide-on-extra-large-only |
Hidden on Extra-large (≥ 1600px) |
.show-on-compact |
Shown on Compact (< 600px) |
.show-on-medium |
Shown on Medium (600 to 839px) |
.show-on-expanded |
Shown on Expanded (840 to 1199px) |
.show-on-expanded-and-up |
Shown on Expanded and wider (≥ 840px) |
.show-on-large |
Shown on Large (1200 to 1599px) |
.show-on-extra-large |
Shown on Extra-large (≥ 1600px) |
.show-on-medium-and-up |
Shown on Medium and wider (≥ 600px) |
.show-on-medium-and-down |
Shown on Compact and Medium (< 840px) |
| Class | Effect |
|---|---|
.hide-on-print | Hidden on paper |
.print-only | Hidden on screen, shown on paper |
Printing also uses the light scheme and hides navigation rails, navigation bars, the FAB menu, snackbars and tooltips. It prints the address after each external link in running text, and keeps headings with the content that follows them.
Usage
<div class="hide-on-compact-only"></div>
<div class="flex hide-on-compact-only gap-2">
<a href="/reports">Reports</a>
<a href="/settings">Settings</a>
</div>
The flex example is hidden below 600px and keeps its flex layout above that
width. Show helpers set display: block !important within their
range. They do not hide content outside it. Use .hide with a
show helper only when block display is appropriate.
Visually hidden
Add visually-hidden to remove an element from sight and
keep it in the accessibility tree, so screen readers still announce it.
Use it for text the layout does not show, such as context that makes
a repeated link unique or the text of a live region. Like
.hide, it is !important.
A focused element with this class stays invisible. Do not put it on a focusable control unless focus is drawn somewhere else, the way a filter chip draws it on its label.
<a href="/orders/42">View<span class="visually-hidden"> order 42</span></a>
Reveal on focus
Use .visually-hidden-focusable for a skip link or a container
that should appear when it or a descendant receives focus. It applies the same
hidden styles only while focus is outside. Do not combine it with
.visually-hidden, which would keep it hidden.
<a class="visually-hidden-focusable" href="#main-content">Skip to content</a>
<main id="main-content" tabindex="-1">
<h1>Page content</h1>
</main>
Spacing
The spacing helpers set margin and padding on any side. Each class combines a margin or padding prefix, a direction infix and a value suffix.
Prefix margin and padding modifiers
| Prefix | Modifies |
|---|---|
m* |
Sets the margin from the infix and suffix. With no infix, it applies to all directions. |
p* |
Sets the padding from the infix and suffix. With no infix, it applies to all directions. |
Infix direction modifiers
| Infix | Direction |
|---|---|
*t |
Applies the modifier to the top side of the element |
*r |
Applies the modifier to the right side of the element |
*b |
Applies the modifier to the bottom side of the element |
*l |
Applies the modifier to the left side of the element |
*s |
Applies the modifier to the inline-start side, following the writing direction |
*e |
Applies the modifier to the inline-end side, following the writing direction |
*x |
Applies the modifier to the left and right sides of the element |
*y |
Applies the modifier to the top and bottom sides of the element |
Suffix values
Append a value suffix to each modifier. Values 0 through 6 work for margin and padding. auto is for margin only.
| Suffix | Value |
|---|---|
*-0 |
0 |
*-1 |
0.25rem |
*-2 |
0.5rem |
*-3 |
0.75rem |
*-4 |
1rem |
*-5 |
1.5rem |
*-6 |
3rem |
*-auto |
auto |
Logical spacing
These helpers use the same scale and !important declarations.
Inline start and end mirror in RTL. The physical spacing classes still work. Do not
combine physical and logical helpers that set the same side.
| Property | Classes |
|---|---|
margin-inline-start | ms-0 through ms-6, ms-auto |
margin-inline-end | me-0 through me-6, me-auto |
padding-inline-start | ps-0 through ps-6 |
padding-inline-end | pe-0 through pe-6 |
<div class="flex align-center gap-2">
<span class="start-align">Account</span>
<a class="ms-auto" href="/settings">Settings</a>
</div>
Physical spacing
Margin helpers
| Property | Prefix | Classes | |||||||
|---|---|---|---|---|---|---|---|---|---|
margin |
m |
m-0 |
m-1 |
m-2 |
m-3 |
m-4 |
m-5 |
m-6 |
m-auto |
margin-top |
mt |
mt-0 |
mt-1 |
mt-2 |
mt-3 |
mt-4 |
mt-5 |
mt-6 |
mt-auto |
margin-right |
mr |
mr-0 |
mr-1 |
mr-2 |
mr-3 |
mr-4 |
mr-5 |
mr-6 |
mr-auto |
margin-bottom |
mb |
mb-0 |
mb-1 |
mb-2 |
mb-3 |
mb-4 |
mb-5 |
mb-6 |
mb-auto |
margin-left |
ml |
ml-0 |
ml-1 |
ml-2 |
ml-3 |
ml-4 |
ml-5 |
ml-6 |
ml-auto |
margin-block |
my |
my-0 |
my-1 |
my-2 |
my-3 |
my-4 |
my-5 |
my-6 |
my-auto |
margin-inline |
mx |
mx-0 |
mx-1 |
mx-2 |
mx-3 |
mx-4 |
mx-5 |
mx-6 |
mx-auto |
| Values | 0 | 0.25rem | 0.5rem | 0.75rem | 1rem | 1.5rem | 3rem | auto | |
Padding helpers
| Property | Prefix | Classes | ||||||
|---|---|---|---|---|---|---|---|---|
padding |
p |
p-0 |
p-1 |
p-2 |
p-3 |
p-4 |
p-5 |
p-6 |
padding-top |
pt |
pt-0 |
pt-1 |
pt-2 |
pt-3 |
pt-4 |
pt-5 |
pt-6 |
padding-right |
pr |
pr-0 |
pr-1 |
pr-2 |
pr-3 |
pr-4 |
pr-5 |
pr-6 |
padding-bottom |
pb |
pb-0 |
pb-1 |
pb-2 |
pb-3 |
pb-4 |
pb-5 |
pb-6 |
padding-left |
pl |
pl-0 |
pl-1 |
pl-2 |
pl-3 |
pl-4 |
pl-5 |
pl-6 |
padding-block |
py |
py-0 |
py-1 |
py-2 |
py-3 |
py-4 |
py-5 |
py-6 |
padding-inline |
px |
px-0 |
px-1 |
px-2 |
px-3 |
px-4 |
px-5 |
px-6 |
| Values | 0 | 0.25rem | 0.5rem | 0.75rem | 1rem | 1.5rem | 3rem | |
Usage
<div class="p-2">
<h5 class="mt-1">The div has a padding 0.5rem and the h5 has a margin-top of 0.25rem</h5>
</div>
Formatting
These classes handle truncation, line clamping, text wrapping, opacity, unstyled lists and hover effects.
Truncation
To truncate a long line of text with an ellipsis, add the class
truncate to the element that contains it. The example below truncates a heading inside a card.
A flex or grid child may also need .min-w-0 to shrink.
This is an extremely long title that will be truncated
<h4 class="truncate">This is an extremely long title that will be truncated</h4>
Line clamp
To cut text to a few lines and end it in an ellipsis, add line-clamp-1,
line-clamp-2 or line-clamp-3. line-clamp-none shows every line
again, so line-clamp-2 expanded:line-clamp-none clamps on compact and medium windows only.
The classes set display, so put them on a child of a flex or grid container, not on the
container. Pad a wrapper rather than the clamped element, because block-end padding shows the top of the
next line.
This card description runs on for several lines, but the class cuts it after the second line and ends that line in an ellipsis, so cards in a row keep the same height.
<p class="line-clamp-2">This card description runs on for several lines…</p>
Text wrapping
| Class | Use |
|---|---|
.break-words | overflow-wrap: anywhere lets long URLs or identifiers wrap within their container. |
.text-nowrap | white-space: nowrap keeps text on one line without clipping or ellipsis. |
.text-wrap | white-space: normal restores ordinary wrapping. |
.text-balance | text-wrap-style: balance evens out the line lengths of a short block, such as a card title. Headings already do this. |
.text-pretty | text-wrap-style: pretty avoids a single short word on the last line. Paragraphs already do this. |
Allow wrapping on narrow screens when keeping a line intact would hide required text. These classes do not change display or overflow.
Opacity
.opacity-0, .opacity-25, .opacity-38, .opacity-50,
.opacity-75 and .opacity-100 set opacity to 0, 0.25, 0.38, 0.5, 0.75 and 1.
38 is the M3 opacity for disabled content. A class overrides a component's own opacity, and unlayered page CSS overrides the class.
Dimmed text still needs enough contrast unless it belongs to a disabled control. Opacity disables and hides nothing:
even at .opacity-0 the element takes clicks and focus and stays in the accessibility tree.
Use disabled, .hide or hidden for that.
<img class="opacity-50" src="pattern.svg" alt="">
Unstyled lists
Add list-unstyled to a <ul> or <ol> to remove its markers
and its inline-start padding. The list keeps its margins, and a list nested inside it keeps its own markers.
WebKit drops the list role from a list without markers, so add role="list" as well. The
semantics checks flag a .list-unstyled list with no role; a list that sets another
role on purpose, such as role="none", passes.
- Invoices
- Receipts
<ul class="list-unstyled" role="list">
<li>Invoices</li>
<li>Receipts</li>
</ul>
Hover
Add hoverable to animate the box shadow, as in the example below. It works
on most elements, but it is meant for cards.
<article class="hoverable">Hoverable article</article>
Pointer
| Class | Declaration |
|---|---|
.pointer-events-none | pointer-events: none. Clicks, taps and hovers on the element and its children reach whatever lies beneath it. |
.pointer-events-auto | pointer-events: auto. A child of a .pointer-events-none element takes pointer input again. |
.cursor-pointer | cursor: pointer |
<div class="relative">
<a href="/photos/42"><img class="w-full" src="..." alt="Fishing boats moored in a harbor at dusk"></a>
<div class="pointer-events-none flex align-end justify-between p-2" style="position: absolute; inset: 0">
<span class="label-large">Photo by Ana Ruiz</span>
<button type="button" class="pointer-events-auto">Hide caption</button>
</div>
</div>
<tr class="cursor-pointer">
<td><a href="/orders/42">Order 42</a></td>
<td>Shipped</td>
</tr>
A click on the caption opens the photo link beneath it, and the button still takes
its own clicks. .pointer-events-none stops the pointer only: the element
and its controls stay in the tab order and still respond to keys. To disable a control,
use disabled; to take a whole region out of use, use inert.
.cursor-pointer changes the cursor and nothing else. Links and buttons
already show it. In the table row above, a page script opens the row's link on a click
anywhere in the row, and keyboard users reach the same link by Tab. An element that
responds to clicks but isn't a link or button still needs a role, a tab stop and key
handling, so use a <button> or <a href> where one fits.
Browser defaults
ExpressiveCSS overrides many default browser styles. Add the
.browser-default class to an element to opt it out of those styles.
| Element | Reverted style |
|---|---|
| SELECT | Browser default select element |
| INPUT | Browser default input |
<select class="browser-default">
<option value="" disabled selected>Choose your option</option>
<option value="1">Option 1</option>
</select>
<input class="browser-default" type="text">