Skip to content

ExpressiveCSS

Browse documentation

Helpers

Helper classes for alignment, visibility, spacing, and common CSS properties.

View as Markdown

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

ClassDeclaration
.block, .inline-blockdisplay: block, display: inline-block
.grid, .inline-griddisplay: grid, display: inline-grid
.grid-auto-fillA grid with as many columns as fit, each at least --grid-column-min wide (240px by default)
.contentsdisplay: contents; the element's box goes away and its children join the parent's layout
.relativeposition: relative
.sticky-topposition: sticky; top: 0
.position-absolute, .position-fixed, .position-staticposition: absolute, position: fixed, position: static
.inset-0inset: 0; the element covers its containing block
.top-0, .bottom-0top: 0, bottom: 0
.start-0, .end-0inset-inline-start: 0, inset-inline-end: 0; they swap sides in RTL
.query-containercontainer-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.

Orders
Returns
Refunds
Payouts
Disputes
<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
.flexdisplay: flex
.inline-flexdisplay: inline-flex
.flex-row, .flex-columnflex-direction
.flex-wrap, .flex-nowrapflex-wrap
.justify-start, .justify-center, .justify-end, .justify-between, .justify-around, .justify-evenlyjustify-content
.align-start, .align-center, .align-end, .align-stretch, .align-baselinealign-items
.flex-1flex: 1 1 0 on a child, so it takes the remaining space
.flex-noneflex: none on a child, so it keeps its content size
.flex-initialflex: 0 1 auto on a child, so it sizes from its content, can shrink and does not grow
.shrink-0flex-shrink: 0 on a child, so it never gets narrower than its basis
.shrink-1flex-shrink: 1 on a child, restoring shrinking while keeping its grow factor and basis
.self-start, .self-center, .self-end, .self-stretchalign-self on a child
.self-autoalign-self: auto on a child, so it follows the parent's align-* again
.order-first, .order-last, .order-noneorder: -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-6gap on the spacing scale, with !important. Also works on grid containers.
.gap-x-0 to .gap-x-6column-gap only, with !important.
.gap-y-0 to .gap-y-6row-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.

Monday
Tuesday
Wednesday
Thursday
Friday
Saturday
<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.

PrefixApplies from
medium:Medium, 600px
expanded:Expanded, 840px
large:Large, 1200px
extra-large:Extra-large, 1600px
Members
<!-- 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.

Quarterly report with a long filename.pdf Sizing guide
<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.

ClassDeclaration
.min-w-0min-width: 0
.min-h-0min-height: 0
.w-full, .h-fullwidth: 100%, height: 100%
.max-w-fullmax-width: 100%
.aspect-1x1, .aspect-4x3, .aspect-16x9aspect-ratio; the height follows the width
.object-cover, .object-containobject-fit on an <img> or <video> with a set ratio
.overflow-x-autooverflow-x: auto
.overflow-y-autooverflow-y: auto
.overflow-hiddenoverflow: 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

ClassDeclaration
.borderedA 1px outline-variant border on every side
.border-top, .border-bottomThe same border on one side
.border-start, .border-endThe 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-fullborder-radius from the matching --md-sys-shape-corner-* token
.corner-cutcorner-shape: bevel. The element's corners become straight cuts of the same size. Browsers without corner-shape round them instead.
16:9
<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)
Print
ClassEffect
.hide-on-printHidden on paper
.print-onlyHidden 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.

PropertyClasses
margin-inline-startms-0 through ms-6, ms-auto
margin-inline-endme-0 through me-6, me-auto
padding-inline-startps-0 through ps-6
padding-inline-endpe-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
ClassUse
.break-wordsoverflow-wrap: anywhere lets long URLs or identifiers wrap within their container.
.text-nowrapwhite-space: nowrap keeps text on one line without clipping or ellipsis.
.text-wrapwhite-space: normal restores ordinary wrapping.
.text-balancetext-wrap-style: balance evens out the line lengths of a short block, such as a card title. Headings already do this.
.text-prettytext-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.

Hoverable article
<article class="hoverable">Hoverable article</article>

Pointer

ClassDeclaration
.pointer-events-nonepointer-events: none. Clicks, taps and hovers on the element and its children reach whatever lies beneath it.
.pointer-events-autopointer-events: auto. A child of a .pointer-events-none element takes pointer input again.
.cursor-pointercursor: 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">

No matching pages

  • Source color

    The seed every generated ramp derives from. Pick one and browse the docs — the whole theme follows. Error does not: it is a fixed hue.

    Default source: Mist Iris.

    ExpressiveCSS presets: Lagoon, Harbor, Breeze, Cobalt, Iris.

    Bold

    Soft

    Mist

    Glow