The page navigation is complete. You may now navigate the page content as you wish.
Skip to main content

Grid

A component used to implement layouts based on CSS grid.

How to use this component

Code tip

While it’s not necessary to be familiar with CSS3 grid specifications to use this component, some knowledge may be helpful in achieving more complex layouts.

A helpful reference with clear examples: CSS Tricks: Complete grid layout guide.

<i80-grid> lays content out in columns of equal width with one of the standard gaps between them, so you don't have to write grid CSS or know all its intricacies. <i80-grid-item> is the optional companion for an item that has to span more than one cell, or that shouldn't be stretched to fill its column.

Basic usage

Code consideration

<i80-grid> is the grid container, so every child you write is a grid item where you wrote it. You only need <i80-grid-item> around a child that spans more than one cell or that shouldn't stretch.

The simplest grid layout is an <i80-grid> with content in it. A grid of equal width “columns” is created by default.

Item 1
Item 2
Item 3
Item 4
<i80-grid>
  <div class="doc-placeholder" style="height: 40px; background: #e4c5f3">Item 1</div>
  <div class="doc-placeholder" style="height: 40px; background: #e5ffd2">Item 2</div>
  <div class="doc-placeholder" style="height: 40px; background: #d2f4ff">Item 3</div>
  <div class="doc-placeholder" style="height: 40px; background: #fff8d2">Item 4</div>
</i80-grid>

Every child of the grid container is stretched to fit evenly within the underlying grid column tracks, behaving as a grid item (for details on what this means, refer to the guide linked at the top of the page).

In some cases it is useful to wrap one or more items in an <i80-grid-item>: to group content together within a column or row, to prevent content from being stretched to fit the underlying grid column width, or to make use of rowspan and colspan in order to create more complex layouts. (See below for more details and examples on these features.)

Keeping an item from stretching

Wrap content in an <i80-grid-item>, with no attributes at all, to prevent it from stretching to fill the grid column.

Stretched badge Non-stretched badge
<i80-grid column-min-width="100%" gap="16">
  <i80-badge color="critical">Stretched badge</i80-badge>
  <i80-grid-item>
    <i80-badge color="success">Non-stretched badge</i80-badge>
  </i80-grid-item>
</i80-grid>

Putting the layout on another element

Accessibility alert

While, by default, the component renders a <div>, we invite consumers to consider which semantic HTML tag is the correct one for the context in which the text is used to meet WCAG Success Criterion 1.3.1 Info and Relationships as the visual experience should match what is presented to the user with assistive technology.

When the box has to be a list or a <nav>, name that element with the tag attribute. <i80-grid> renders it around the children and steps out of the layout, so the elements you write yourself become the grid items.

tag="li", tag="td" and tag="th" are the exception: they would leave our element between the list or the row and its item, which loses the list or table semantics, and the element warns about it in the console. Write the <li>, <td> or <th> yourself as a direct child of the list or row. An item that has to span gets the i80-layout-grid-item class and the --i80-layout-grid-column-span custom property directly, as in this example:

  • All plans
  • Archive and everything in it
  • Shared with me
  • <!-- tag="ul" puts the layout on a real list; the <li> elements are its items -->
    <i80-grid tag="ul" style="margin: 0; padding: 0; list-style: none">
      <li>All plans</li>
      <li class="i80-layout-grid-item" style="--i80-layout-grid-column-span: 2">Archive and everything in it</li>
      <li>Shared with me</li>
    </i80-grid>

    Space between items

    To control the spacing between grid items, use the gap attribute.

    Pass a single value to set equal spacing between columns & rows.

    Item 1
    Item 2
    Item 3
    Item 4
    <i80-grid column-min-width="50%" gap="16">
      <div class="doc-placeholder" style="height: 40px; background: #e4c5f3">Item 1</div>
      <div class="doc-placeholder" style="height: 40px; background: #e5ffd2">Item 2</div>
      <div class="doc-placeholder" style="height: 40px; background: #d2f4ff">Item 3</div>
      <div class="doc-placeholder" style="height: 40px; background: #fff8d2">Item 4</div>
    </i80-grid>

    To differentiate the vertical and horizontal spacing between items when they wrap on multiple rows, give gap two values separated by a space, as in CSS.

    Item 1
    Item 2
    Item 3
    Item 4
    <i80-grid column-min-width="50%" gap="16 48">
      <div class="doc-placeholder" style="height: 40px; background: #e4c5f3">Item 1</div>
      <div class="doc-placeholder" style="height: 40px; background: #e5ffd2">Item 2</div>
      <div class="doc-placeholder" style="height: 40px; background: #d2f4ff">Item 3</div>
      <div class="doc-placeholder" style="height: 40px; background: #fff8d2">Item 4</div>
    </i80-grid>

    The first value refers to the vertical gap between “rows” of items (row-gap in CSS), the second one to the horizontal spacing between “columns” of items (column-gap in CSS).

    gap accepts only pre-defined values, it can’t be used to provide custom spacing values. Refer to the Attributes section for details on which values are accepted.

    If you need to provide custom spacing values, see below how you can use a special escape hatch for this.

    Other gap sizes

    If you absolutely have to use non-standard spacing value(s) for the grid gap, you can set the internal --i80-layout-grid-row-gap and --i80-layout-grid-column-gap CSS variables to custom values (e.g., via a local CSS class or an inline style).

    Item 1
    Item 2
    <!-- Any gap other than the standard ones is set as the two CSS variables -->
    <i80-grid style="--i80-layout-grid-column-gap: 13px">
      <div class="doc-placeholder" style="height: 40px; background: #e4c5f3">Item 1</div>
      <div class="doc-placeholder" style="height: 40px; background: #e5ffd2">Item 2</div>
    </i80-grid>

    In this case we’re overwriting only the “column” gap value.

    If the grid items are wrapping on multiple lines, you have to overwrite both the “row” and “column” gap values.

    Item 1
    Item 2
    Item 3
    Item 4
    <i80-grid column-min-width="50%" style="--i80-layout-grid-row-gap: 10px; --i80-layout-grid-column-gap: 0.625rem">
      <div class="doc-placeholder" style="height: 40px; background: #e4c5f3">Item 1</div>
      <div class="doc-placeholder" style="height: 40px; background: #e5ffd2">Item 2</div>
      <div class="doc-placeholder" style="height: 40px; background: #d2f4ff">Item 3</div>
      <div class="doc-placeholder" style="height: 40px; background: #fff8d2">Item 4</div>
    </i80-grid>

    Column widths

    There are two ways of controlling the column widths: column-min-width and column-width. A column has one width, so the two are not to be combined — the element warns in the console and uses column-min-width if both are there.

    • column-min-width creates a semi-fluid layout. If there are fewer items than fit in a row, columns will automatically adjust so that their combined widths add up to 100%. If the combined widths of columns in a row add up to more than 100%, they will automatically wrap to the next row as needed to fit.

    • column-width creates a more “fixed” layout. The column widths will remain consistent no matter how many items are in a row. It has a variant per breakpoint to define responsive views.

    Column min width

    Set column-min-width to create a more fluid, “semi-responsive“ layout.

    Note: The gap size will be automatically subtracted from the column-min-width. Take this into account when specifying a min width value.

    Semi-fluid layout behavior using percentage values

    The column widths in a single row automatically adjust to maintain a total width of 100%.

    With 3 items

    Item 1
    Item 2
    Item 3

    With 2 items

    Item 1
    Item 2

    With 1 item

    Item 1
    <p class="i80-typography-display-200">With 3 items</p>
    <i80-grid column-min-width="33.33%" gap="16">
      <div class="doc-placeholder" style="height: 40px; background: #e4c5f3">Item 1</div>
      <div class="doc-placeholder" style="height: 40px; background: #e5ffd2">Item 2</div>
      <div class="doc-placeholder" style="height: 40px; background: #d2f4ff">Item 3</div>
    </i80-grid>
    
    <hr class="doc-code-group-hr">
    
    <p class="i80-typography-display-200">With 2 items</p>
    <i80-grid column-min-width="33.33%" gap="16">
      <div class="doc-placeholder" style="height: 40px; background: #e4c5f3">Item 1</div>
      <div class="doc-placeholder" style="height: 40px; background: #e5ffd2">Item 2</div>
    </i80-grid>
    
    <hr class="doc-code-group-hr">
    
    <p class="i80-typography-display-200">With 1 item</p>
    <i80-grid column-min-width="33.33%" gap="16">
      <div class="doc-placeholder" style="height: 40px; background: #e4c5f3">Item 1</div>
    </i80-grid>
    Semi-responsive layout using fixed unit values

    Specifying column min-widths using fixed units such as pixels, allows you to create layouts which are “automatically” responsive. To create fully responsive layouts using defined breakpoints, see column width.

    Grid within a wider view

    Narrow your browser window to see the responsive behavior.

    Item 1
    Item 2
    Item 3
    Item 4
    <i80-grid column-min-width="180px" gap="16">
      <div class="doc-placeholder" style="height: 40px; background: #e4c5f3">Item 1</div>
      <div class="doc-placeholder" style="height: 40px; background: #e5ffd2">Item 2</div>
      <div class="doc-placeholder" style="height: 40px; background: #d2f4ff">Item 3</div>
      <div class="doc-placeholder" style="height: 40px; background: #fff8d2">Item 4</div>
    </i80-grid>
    The same grid within a narrower view

    At the specified column min width, columns are forced to stack in this narrower view.

    Item 1
    Item 2
    Item 3
    Item 4
    <div class="doc-grid-mobile-view">
      <i80-grid column-min-width="160px" gap="16">
          <div class="doc-placeholder" style="height: 40px; background: #e4c5f3">Item 1</div>
        <div class="doc-placeholder" style="height: 40px; background: #e5ffd2">Item 2</div>
        <div class="doc-placeholder" style="height: 40px; background: #d2f4ff">Item 3</div>
        <div class="doc-placeholder" style="height: 40px; background: #fff8d2">Item 4</div>
      </i80-grid>
    </div>

    Column width

    To create column layouts that are more “fixed” vs. fluid, use column-width to specify a width for the columns. Items will respect the defined width instead of stretching to fill out a single column row.

    Note: The gap size will be automatically subtracted from the column-width. Take this into account when specifying width values.

    Non-responsive columns

    A single column-width creates a non-responsive column layout.

    With 4 items

    Item 1
    Item 2
    Item 3
    Item 4

    With 2 items

    Item 1
    Item 2

    With 1 item

    Item 1
    <p class="i80-typography-display-200">With 4 items</p>
    <i80-grid column-width="33.33%" gap="16">
      <div class="doc-placeholder" style="height: 40px; background: #e4c5f3">Item 1</div>
      <div class="doc-placeholder" style="height: 40px; background: #e5ffd2">Item 2</div>
      <div class="doc-placeholder" style="height: 40px; background: #d2f4ff">Item 3</div>
      <div class="doc-placeholder" style="height: 40px; background: #fff8d2">Item 4</div>
    </i80-grid>
    
    <hr class="doc-code-group-hr">
    
    <p class="i80-typography-display-200">With 2 items</p>
    <i80-grid column-width="33.33%" gap="16">
      <div class="doc-placeholder" style="height: 40px; background: #e4c5f3">Item 1</div>
      <div class="doc-placeholder" style="height: 40px; background: #e5ffd2">Item 2</div>
    </i80-grid>
    
    <hr class="doc-code-group-hr">
    
    <p class="i80-typography-display-200">With 1 item</p>
    <i80-grid column-width="33.33%" gap="16">
      <div class="doc-placeholder" style="height: 40px; background: #e4c5f3">Item 1</div>
    </i80-grid>
    Responsive columns

    Instead of one column-width, you can set column-width-sm, column-width-md, column-width-lg, column-width-xl and column-width-xxl to define responsive column widths for the five supported views, based on the I80 breakpoint values.

    See the “Responsive layouts” section for more details on responsive layout breakpoints and behavior.

    With all views defined
    Item 1
    Item 2
    Item 3
    Item 4
    Item 5
    <i80-grid column-width-sm="100%" column-width-md="50%" column-width-lg="33.33%" column-width-xl="25%" column-width-xxl="20%" gap="16">
      <div class="doc-placeholder" style="height: 40px; background: #e4c5f3">Item 1</div>
      <div class="doc-placeholder" style="height: 40px; background: #e5ffd2">Item 2</div>
      <div class="doc-placeholder" style="height: 40px; background: #d2f4ff">Item 3</div>
      <div class="doc-placeholder" style="height: 40px; background: #fff8d2">Item 4</div>
      <div class="doc-placeholder" style="height: 40px; background: #f3d9c5">Item 5</div>
    </i80-grid>
    With only sm & lg views defined

    If you do not set a value for the sm view, columns in this view and views inheriting from it will behave as undefined and will never wrap as demonstrated in the Basic usage example.

    Values defined for smaller views are inherited by larger views so you do not need to specify values for all breakpoints if not needed for your layout.

    Item 1
    Item 2
    Item 3
    Item 4
    Item 5
    <i80-grid column-width-sm="50%" column-width-lg="33.33%" gap="16">
      <div class="doc-placeholder" style="height: 40px; background: #e4c5f3">Item 1</div>
      <div class="doc-placeholder" style="height: 40px; background: #e5ffd2">Item 2</div>
      <div class="doc-placeholder" style="height: 40px; background: #d2f4ff">Item 3</div>
      <div class="doc-placeholder" style="height: 40px; background: #fff8d2">Item 4</div>
      <div class="doc-placeholder" style="height: 40px; background: #f3d9c5">Item 5</div>
    </i80-grid>

    Alignment

    Use the align attribute to align grid items to the "start", "end", "center" or to "stretch" them within the grid parent. The default is stretch.

    Note: the grid will need a height set for the effect to be visible.

    Item 1
    Item 2
    Item 3
    Item 4
    <div class="doc-grid-mobile-view">
      <i80-grid column-min-width="50px" gap="16" align="center" style="height: 100%">
        <div class="doc-placeholder" style="height: 40px; background: #e4c5f3">Item 1</div>
        <div class="doc-placeholder" style="height: 40px; background: #e5ffd2">Item 2</div>
        <div class="doc-placeholder" style="height: 40px; background: #d2f4ff">Item 3</div>
        <div class="doc-placeholder" style="height: 40px; background: #fff8d2">Item 4</div>
      </i80-grid>
    </div>

    Spanning columns and rows

    Use the colspan and rowspan attributes of <i80-grid-item> to set the number of columns or rows an item should occupy. Both have a variant per breakpoint to define responsive views.

    Note: By default, if a height is set on the grid, grid row heights will stretch proportionally to fill it. To instead make a row conform to the minimum height of its content, you can pass an inline style as shown in the example.

    Non-responsive example

    A single colspan or rowspan value creates a non-responsive layout.

    In this example, an underlying 4-column grid is specified by setting a column-min-width of “25%”. colspan and rowspan are used to create a flexible layout roughly resembling a typical web page layout.

    Item 1
    Item 2
    Item 3
    Item 4
    <div style="height: 400px; border: 1px solid">
      <i80-grid column-min-width="25%" gap="12" style="height: 100%; grid-template-rows: min-content">
        <i80-grid-item colspan="4">
          <div class="doc-placeholder" style="padding: 1em; background: #e4c5f3">Item 1</div>
        </i80-grid-item>
        <i80-grid-item rowspan="3">
          <div class="doc-placeholder" style="height: 100%; background: #e5ffd2">Item 2</div>
        </i80-grid-item>
        <i80-grid-item colspan="3">
          <div class="doc-placeholder" style="height: 100%; background: #d2f4ff">Item 3</div>
        </i80-grid-item>
        <i80-grid-item colspan="3" rowspan="2">
          <div class="doc-placeholder" style="height: 100%; background: #fff8d2">Item 4</div>
        </i80-grid-item>
      </i80-grid>
    </div>

    Responsive example using breakpoints

    See the “Responsive layouts” section for more details on responsive layout breakpoints and behavior.

    Instead of one value, you can set colspan-sm … colspan-xxl and rowspan-sm … rowspan-xxl to define values for the five supported views, based on the I80 breakpoint values.

    In this example, both the grid's column widths and the span of 2 items use responsive values so the layout shifts when viewed in small screens. Narrow your browser window to see the responsive behavior.

    Item 1
    Item 2
    Item 3
    Item 4
    <i80-grid column-width-sm="100%" column-width-md="33.33%" gap="12">
      <i80-grid-item colspan-sm="1" colspan-md="2">
        <div class="doc-placeholder" style="height: 40px; background: #e4c5f3">Item 1</div>
      </i80-grid-item>
      <div class="doc-placeholder" style="height: 40px; background: #e5ffd2">Item 2</div>
      <div class="doc-placeholder" style="height: 40px; background: #d2f4ff">Item 3</div>
      <i80-grid-item colspan-sm="1" colspan-md="2">
        <div class="doc-placeholder" style="height: 40px; background: #fff8d2">Item 4</div>
      </i80-grid-item>
    </i80-grid>

    Responsive layouts

    We use a mobile-first layout approach for the responsive views, so values defined for smaller views are inherited if not overridden by larger views. Therefore, it is not necessary to set values for all breakpoints.

    Responsive features

    Responsive layout options are supported by the column width of the grid and by the span of a grid item. There are five supported views based on the I80 breakpoint values.

    Supported breakpoints

    • sm view = mobile first approach (mobile devices)
    • md view = 768px and above (tablets and small laptops)
    • lg view = 1088px and above (large laptops and desktops)
    • xl = 1440px and above (extra large desktops)
    • xxl = 1920px and above (extra extra large desktops)

    Common layout patterns

    Important

    The examples below are meant to show how one could use <i80-grid> to implement certain common/standard UI patterns. They're not meant to be taken literally as they are and be used in production code.

    Below are examples of common layout patterns that can be achieved with <i80-grid> in combination with other I80 components.

    Card layout

    The following example makes use of nested grids and Flex to achieve its layout. This may be overkill in actual practice but demonstrates the possibilities for achieving layouts with just these layout elements alone.

    A responsive layout is used so that the cards stack in the smallest view while being laid out into three columns in all other views.

    Basic 3-column card layout

    Active resources 5 active resources There are 5 active resources inside this project. View active resources Card #2 Card #3
    <i80-grid column-width-sm="100%" column-width-md="33.33%" gap="32">
      <i80-card level="mid" border style="padding: 24px">
        <i80-grid column-min-width="100%" gap="16">
          <i80-flex align="center" gap="8">
            <i80-icon-tile icon="cloud" size="small"></i80-icon-tile>
            <i80-text tag="h2" variant="display" size="300">Active resources</i80-text>
          </i80-flex>
          <i80-grid column-min-width="100%" gap="8">
            <i80-grid-item>
              <i80-badge color="success" icon="check-circle">5 active resources</i80-badge>
            </i80-grid-item>
            <i80-text tag="p">There are 5 active resources inside this project.</i80-text>
          </i80-grid>
          <i80-link-standalone href="#resources" icon="arrow-right" icon-position="trailing">View active resources</i80-link-standalone>
        </i80-grid>
      </i80-card>
    
      <i80-card level="mid" border style="padding: 24px">
        <i80-text tag="h2" variant="display" size="300">Card #2</i80-text>
      </i80-card>
    
      <i80-card level="mid" border style="padding: 24px">
        <i80-text tag="h2" variant="display" size="300">Card #3</i80-text>
      </i80-card>
    </i80-grid>

    More complex layout

    Wrap content in an <i80-grid-item> as needed to achieve more complex layouts.

    How this layout works

    We first establish an underlying grid structure of three columns by setting column-width-md="33.33%" on the grid. The colspan-md of some of the <i80-grid-item> children is then used to make them span two of the underlying grid columns, creating a more complex layout.

    column-width-sm="100%" and colspan-sm="1" make the content items stack in the smallest view.

    In Preview Better together Plans now work together with shared calendars. The two together let a team plan the work and see it in the calendar it already lives by. content content What you can add to a plan
  • Tasks Break the work down and give each part an owner.
  • Milestones Mark the dates the plan is measured by.
  • <i80-grid column-width-sm="100%" column-width-md="33.33%" gap="24">
      <i80-grid-item colspan-sm="1" colspan-md="2">
        <i80-card level="mid" border style="padding: 24px; background: radial-gradient(151.34% 168.34% at 0 0, #f6f9ff 0, #ebf2ff 100%)">
          <i80-grid column-width="100%" gap="16">
            <i80-grid-item>
              <i80-badge type="outlined" color="highlight">In Preview</i80-badge>
            </i80-grid-item>
            <i80-text tag="h2" variant="display" size="300" weight="bold">Better together</i80-text>
            <i80-text tag="p" weight="semibold">Plans now work together with shared calendars.</i80-text>
            <i80-text tag="p">The two together let a team plan the work and see it in the calendar it already lives by.</i80-text>
          </i80-grid>
        </i80-card>
      </i80-grid-item>
    
      <i80-card level="mid" border style="padding: 24px">
        <i80-text tag="h2" variant="display" size="300">content</i80-text>
      </i80-card>
    
      <i80-card level="mid" border style="padding: 24px">
        <i80-text tag="h2" variant="display" size="300">content</i80-text>
      </i80-card>
    
      <i80-grid-item colspan-sm="1" colspan-md="2">
        <i80-card level="mid" border style="padding: 24px">
          <i80-grid column-min-width="100%" gap="16">
            <i80-text tag="h2" variant="display" size="300">What you can add to a plan</i80-text>
            <i80-grid column-min-width="50%" gap="24" tag="ul" class="doc-grid-plain-list">
              <li>
                <i80-grid column-min-width="100%" gap="8">
                  <i80-text tag="p" weight="semibold">Tasks</i80-text>
                  <i80-text tag="p">Break the work down and give each part an owner.</i80-text>
                </i80-grid>
              </li>
              <li>
                <i80-grid column-min-width="100%" gap="8">
                  <i80-text tag="p" weight="semibold">Milestones</i80-text>
                  <i80-text tag="p">Mark the dates the plan is measured by.</i80-text>
                </i80-grid>
              </li>
            </i80-grid>
          </i80-grid>
        </i80-card>
      </i80-grid-item>
    </i80-grid>

    Attributes

    <i80-grid> renders this component. Everything it understands:

    Attribute Values Default Notes
    column-min-width CSS length The width a column starts from and stretches up from, so a short row still fills the space and a long one wraps.
    column-width CSS length The width a column keeps, however many items there are. Not to be combined with column-min-width.
    column-width-sm · column-width-md · column-width-lg · column-width-xl · column-width-xxl CSS length The same, per breakpoint (see Foundations/Breakpoints). Smaller views are inherited by larger ones, so only the ones that change need a value.
    align start · center · end · stretch stretch How the items sit in their row (align-items). Needs a height on the grid to be visible.
    gap 0 · 4 · 8 · 12 · 16 · 24 · 32 · 48 0 One value for both gaps, or two — "16 48" is a row gap of 16 and a column gap of 48. The gap is taken off the column width for you. For anything else set --i80-layout-grid-row-gap and --i80-layout-grid-column-gap in a style attribute.
    tag element name Renders that element around the children and puts the layout on it, for when the box has to be a list or a <nav>.
    i80-grid-item colspan · rowspan number 1 How many columns and rows the item spans.
    i80-grid-item colspan-sm … colspan-xxl · rowspan-sm … rowspan-xxl number The same, per breakpoint.
    i80-grid-item tag element name As above, for the item.

    The tag keeps any native element you write inside it, so a server-rendered form, link or button works as it is. See Web Components for loading i80.js and the reference for these examples running.

    0.1.0

    Første i80-version (fork af upstream, se core/UPSTREAM.md).