Making a tab interface with CSS is a endless matter on this planet of contemporary internet growth. Are they potential? If sure, may they be accessible? I wrote methods to construct them the primary time 9 lengthy years in the past, and methods to combine accessible practices into them.
Though my answer then may probably nonetheless be utilized in the present day, I’ve landed on a extra trendy strategy to CSS tabs utilizing the 
First, the HTML
Let’s begin by establishing the HTML construction. We are going to want a set of 
.grid. Every 
 will likely be an .merchandise as you may think every one being a tab within the interface.
  
  
    First merchandise
    
  
  
    Second merchandise
    
  
  
    Third merchandise
    
  

These don’t appear to be true tabs but! But it surely’s the correct construction we would like earlier than we get into CSS, the place we’ll put CSS Grid and Subgrid to work.
Subsequent, the CSS
Let’s arrange the grid for our wrapper factor utilizing — you guessed it — CSS Grid. Mainly what we’re making is a three-column grid, one column for every tab (or .merchandise), with a little bit of spacing between them.
We’ll additionally arrange two rows within the .grid, one which’s sized to the content material and one which maintains its proportion with the accessible area. The primary row will maintain our tabs and the second row is reserved for the airing the lively tab panel.
.grid {
  show: grid;
  grid-template-columns: repeat(3, minmax(200px, 1fr));
  grid-template-rows: auto 1fr;
  column-gap: 1rem;
}Now we’re wanting a little bit extra tab-like:

Subsequent, we have to arrange the subgrid for our tab components. We wish subgrid as a result of it permits us to make use of the prevailing .grid strains with out nesting a completely new grid with new strains. Every little thing aligns properly this fashion.
So, we’ll set every tab — the 
.grid‘s strains with subgrid.
particulars {
  show: grid;
  grid-template-columns: subgrid;
  grid-template-rows: subgrid;
}Moreover, we would like every tab factor to fill your complete .grid, so we set it up in order that the 
grid-column and grid-row properties:
particulars {
  show: grid;
  grid-template-columns: subgrid;
  grid-template-rows: subgrid;
  grid-column: 1 / -1;
  grid-row: 1 / span 3;
}It seems a little bit wonky at first as a result of the three tabs are stacked proper on high of one another, however they cowl your complete .grid which is strictly what we would like.

Subsequent, we’ll place the tab panel content material within the second row of the subgrid and stretch it throughout all three columns. We’re utilizing ::details-content (good assist, however not but in WebKit on the time of writing) to focus on the panel content material, which is good as a result of meaning we don’t have to arrange one other wrapper within the markup merely for that goal.
particulars::details-content {
  grid-row: 2; /* place within the second row */
  grid-column: 1 / -1; /* cowl all three columns */
  padding: 1rem;
  border-bottom: 2px strong dodgerblue;
}The factor a couple of tabbed interface is that we solely wish to present one open tab panel at a time. Fortunately, we are able to choose the [open] state of the 
::details-content of any tab that’s :not([open])by utilizing enabling selectors:
particulars:not([open])::details-content {
  show: none;
}We nonetheless have overlapping tabs, however the one tab panel we’re displaying is presently open, which cleans issues up fairly a bit:

Turning 
 into tabs
Now on to the enjoyable stuff! Proper now, all of our tabs are visually stacked. We wish to unfold these out and distribute them evenly alongside the .grid‘s high row. Every 
 offering each the tab label and button that toggles every one open and closed.
Let’s place the 
 tab is in an [open] state:
abstract {
  grid-row: 1; /* First subgrid row */
  show: grid;
  padding: 1rem; /* Some respiratory room */
  border-bottom: 2px strong dodgerblue;
  cursor: pointer; /* Replace the cursor when hovered */
}
/* Type the  factor when  is [open] */
particulars[open] abstract {
  font-weight: daring;
} Our tabs are nonetheless stacked, however how now we have some gentle kinds utilized when a tab is open:

We’re virtually there! The very last thing is to place the 
:nth-of-type pseudo to pick every one individually by their order within the HTML:
/* First merchandise in first column */
particulars:nth-of-type(1) abstract {
  grid-column: 1 / span 1;
}
/* Second merchandise in second column */
particulars:nth-of-type(2) abstract {
  grid-column: 2 / span 1;
}
/* Third merchandise in third column */
particulars:nth-of-type(3) abstract {
  grid-column: 3 / span 1;
}Test that out! The tabs are evenly distributed alongside the subgrid’s high row:

Sadly, we are able to’t use loops in CSS (but!), however we are able to use variables to maintain our kinds DRY:
abstract {
  grid-column: var(--n) / span 1;
}Now we have to set the --n variable for every 
  
    First merchandise
    
  
  
    Second merchandise
    
  
  
    Third merchandise
    
  
Once more, as a result of loops aren’t a factor in CSS in the meanwhile, I have a tendency to achieve for a templating language, particularly Liquid, to get some looping motion. This manner, there’s no have to explicitly write the HTML for every tab:
{% for merchandise in itemList %}
  
{% endfor %}You possibly can roll with a special templating language, in fact. There are lots on the market in case you like conserving issues concise!
Remaining touches
OK, I lied. There’s another factor we must do. Proper now, you’ll be able to click on solely on the final 
 items are stacked on high of one another in a approach the place the final one is on high of the stack.
You may need already guessed it: we have to put our 
z-index.
abstract {
  z-index: 1;
}Right here’s the complete working demo:
Accessibility
The 
Replace: Nathan Knowler chimed in with some glorious factors over on Mastodon. Adrian Roselli buzzed in with extra context within the feedback as effectively.
It’s 2025, and we are able to create tabs with HTML and CSS solely with none hacks. I don’t find out about you, however this developer is blissful in the present day, even when we nonetheless want a little bit persistence for browsers to completely assist these options.
 
                                








