CSS-Only Tabs Using Details, Grid, and Subgrid

Creating a tab interface using CSS remains a popular topic in web development. Are they achievable? If so, can they be accessible? I first explained how to create them nine years ago and how to incorporate accessible practices into them.

While my earlier solution might still be relevant, I’ve developed a more modern method using the `

` element combined with CSS Grid and Subgrid.

First, the HTML:

Start by setting up the HTML structure with a set of `

` elements inside a parent wrapper called `.grid`. Each `

` will be an `.item`, representing a tab in the interface.

First item
Second item
Third item

These don’t look like true tabs yet, but it’s the right structure before implementing CSS with CSS Grid and Subgrid.

Next, the CSS:

Set up the grid for the wrapper element using CSS Grid. Create a three-column grid, one column for each tab, with some spacing between them. Also, set up two rows in the `.grid`, one sized to the content and another that maintains its proportion with the available space. The first row holds the tabs, and the second row displays the active tab panel.

“`css
.grid {
display: grid;
grid-template-columns: repeat(3, minmax(200px, 1fr));
grid-template-rows: auto 1fr;
column-gap: 1rem;
}
“`

Now, set up the subgrid for the tab elements. Use subgrid to align with the main `.grid` lines without nesting a new grid. Set each `

` element as a grid and inherit the main `.grid`’s lines with `subgrid`.

“`css
details {
display: grid;
grid-template-columns: subgrid;
grid-template-rows: subgrid;
}
“`

Ensure each tab element fills the entire `.grid` by using `grid-column` and `grid-row` properties:

“`css
details {
display: grid;
grid-template-columns: subgrid;
grid-template-rows: subgrid;
grid-column: 1 / -1;
grid-row: 1 / span 3;
}
“`

Next, position the tab panel content in the second row of the subgrid and stretch it across all three columns using `::details-content`:

“`css
details::details-content {
grid-row: 2; /* position in the second row */
grid-column: 1 / -1; /* cover all three columns */
padding: 1rem;
border-bottom: 2px solid dodgerblue;
}
“`

To show only one open tab panel at a time, select the `[open]` state of the `

` elements and hide the `::details-content` of any tab that is `:not([open])`:

“`css
details:not([open])::details-content {
display: none;
}
“`

Turning `

` into tabs:

Distribute the tabs evenly along the `.grid`’s top row. Each `

` element contains a `

` for the tab label and button. Place the `

` in the first subgrid row and apply light styling when a tab is `[open]`:

“`css
summary {
grid-row: 1; /* First subgrid row */
display: grid;
padding: 1rem; /* Some breathing room */
border-bottom: 2px solid dodgerblue;
cursor: pointer; /* Update the cursor when hovered */
}

/* Style the

element when

is [open] */
details[open] summary {
font-weight: bold;
}
“`

Position the `

` elements in the subgrid’s columns using `:nth-of-type`:

“`css
/* First item in first column */
details:nth-of-type(1) summary {
grid-column: 1 / span 1;
}
/* Second item in second column */
details:nth-of-type(2) summary {
grid-column: 2 / span 1;
}
/* Third item in third column */
details:nth-of-type(3) summary {
grid-column: 3 / span 1;
}
“`

Use variables to keep styles DRY:

“`css
summary {
grid


Discover more from WIREDGORILLA

Subscribe to get the latest posts sent to your email.

Similar Posts