Eunomia v1.0.0-beta.2
AllAngularReactNext.jsJavaScriptVue
EunomiaSalmonForestVioletOceanGoldFireCustom…
🇬🇧 English🇫🇷 Français

Grid utilities

Plain CSS grid utility classes for laying out form fields and content blocks without hand-writing display: grid each time: .eun-grid plus one of eleven layout modifiers, all built on the spacing scale. Most fixed-column variants collapse to a single column below 767px; the lead layouts keep their column at every width instead, and the gallery and panel layouts don't need to collapse in the first place, see their own sections below for why.

Halves

Two equal columns, using the --halves modifier.

1
2
<div class="eun-grid eun-grid--halves">
  <eun-button>First</eun-button>
  <eun-button>Second</eun-button>
</div>

Uneven thirds

A narrow column plus a wide one, in either order, using the --thirds-1-2 or --thirds-2-1 modifier.

1 part
2 parts
2 parts
1 part
<div class="eun-grid eun-grid--thirds-1-2">
  <div>1 part</div>
  <div>2 parts</div>
</div>

Equal thirds

Three equal columns, using the --thirds-equal modifier.

1
2
3
<div class="eun-grid eun-grid--thirds-equal">
  <div>1</div>
  <div>2</div>
  <div>3</div>
</div>

2×2 grid

A 2×2 grid, using the --2x2 modifier, for a compact block of four related fields.

1
2
3
4
<div class="eun-grid eun-grid--2x2">
  <div>1</div>
  <div>2</div>
  <div>3</div>
  <div>4</div>
</div>

Sidebar layouts

Two equal columns, using the --sidebar-left or --sidebar-right modifier. The first element spans both rows in its own column, letting a single nav block run the full height alongside two stacked blocks in the other column.

Sidebar
Main
Secondary
<div class="eun-grid eun-grid--sidebar-left">
  <nav>Sidebar</nav>
  <main>Main content</main>
  <aside>Secondary content</aside>
</div>

Lead layouts

Two columns, using the --lead-left or --lead-right modifier. Like the sidebar layouts above, the first element spans both rows in its own column, but that column sizes itself to its content (grid-template-columns: auto 1fr) instead of taking an equal share, built for a leading icon, number, or avatar next to a stacked title and description, rather than a full-width sidebar.

01
Title
Description
<div class="eun-grid eun-grid--lead-left">
  <eun-icon name="bolt" size="24"></eun-icon>
  <span class="title">Instant delivery</span>
  <p class="description">Ships within the hour.</p>
</div>

The auto column sizes itself to the lead element's own natural content size, which suits a small icon or a couple of digits. Give that element width: 100%; height: 100% instead (object-fit: cover too, for an image) to have it fill the column completely, edge to edge across both rows, rather than sitting at its own content size: useful for a photo or a color swatch running the full height next to a stacked title and description.

Photo
Alice Martin
Product Designer
<div class="eun-grid eun-grid--lead-left">
  <img class="avatar" src="/images/alice.jpg" alt="" />
  <span class="title">Alice Martin</span>
  <p class="description">Product Designer</p>
</div>
.avatar {
  width: 100%;
  height: 100%;
  object-fit: cover;
  border-radius: var(--eun-borderRadius-m);
}

Gallery grid

An unknown, variable number of equal tiles, using the --gallery modifier: as many columns as fit at --eun-grid-min-width (220px by default) each, wrapping to further rows on its own. Unlike every variant above, this one is never forced to a single column below 767px, since repeat(auto-fill, minmax(...)) already reflows continuously at any width on its own, a fixed breakpoint would only fight that.

<div class="eun-grid eun-grid--gallery" style="--eun-grid-min-width: 220px;">
  <eun-card>1</eun-card>
  <eun-card>2</eun-card>
  <eun-card>3</eun-card>
  <!-- however many more -->
</div>

Panel layout

A header, a body that takes whatever room is left, and a footer, using the --panel modifier (grid-template-rows: auto 1fr auto), a dialog's or a card's own internal structure, rather than a multi-column layout. The 1fr body row only actually has "room left" to give once the grid itself has a height (the viewport, a fixed height, or a flex/grid ancestor that stretches it) ; a body that can overflow still needs its own overflow-y: auto, the grid track alone doesn't add scrolling.

Header
Body
Footer
<div class="eun-grid eun-grid--panel" style="height: 100%;">
  <header>Header</header>
  <div style="overflow-y: auto;">Body</div>
  <footer>Footer</footer>
</div>

Reference

Class Layout
eun-grid eun-grid--halves 1fr 1fr
eun-grid eun-grid--thirds-1-2 1fr 2fr
eun-grid eun-grid--thirds-2-1 2fr 1fr
eun-grid eun-grid--thirds-equal 1fr 1fr 1fr
eun-grid eun-grid--2x2 repeat(2, 1fr), 2 rows
eun-grid eun-grid--sidebar-left 1fr 1fr, first child spans both rows on the left
eun-grid eun-grid--sidebar-right 1fr 1fr, first child spans both rows on the right
eun-grid eun-grid--lead-left auto 1fr, first child spans both rows on the left
eun-grid eun-grid--lead-right 1fr auto, first child spans both rows on the right
eun-grid eun-grid--gallery repeat(auto-fill, minmax(220px, 1fr))
eun-grid eun-grid--panel a single column, auto 1fr auto rows

Every variant shares the same gap (from the spacing scale): --eun-grid-column-gap (default --eun-space-m) between columns, --eun-grid-row-gap (default --eun-space-s, tighter, since a wrapped row is usually closer content like a title stacked over its description) between rows. Both are plain CSS custom properties, so either can be overridden per instance. Most fixed-column variants collapse to a single column on small screens, with no separate mobile markup needed; the lead layouts are the deliberate exception, since a leading icon, number, or avatar reads as attached to the title next to it rather than as a section of its own, so it keeps its column instead of stacking above the title/description. The gallery already reflows on its own, and the panel is already a single column.