Skip to content

Commit 58998a1

Browse files
committed
Add details tabbed content article
1 parent 975546f commit 58998a1

File tree

3 files changed

+124
-0
lines changed

3 files changed

+124
-0
lines changed

content/languages/css.yaml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -166,6 +166,8 @@ references:
166166
https://developer.mozilla.org/en-US/docs/Web/CSS/display#table
167167
'display: table-cell': >-
168168
https://developer.mozilla.org/en-US/docs/Web/CSS/display#table-cell
169+
'display: contents': >-
170+
https://developer.mozilla.org/en-US/docs/Web/CSS/display#contents
169171
align-items: >-
170172
https://developer.mozilla.org/en-US/docs/Web/CSS/align-items
171173
align-content: >-
@@ -358,3 +360,5 @@ references:
358360
https://developer.mozilla.org/en-US/docs/Web/CSS/max-block-size
359361
inset: >-
360362
https://developer.mozilla.org/en-US/docs/Web/CSS/inset
363+
'::details-content': >-
364+
https://developer.mozilla.org/en-US/docs/Web/CSS/::details-content

content/languages/html.yaml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,3 +4,5 @@ name: HTML
44
additionalReferences: [css, javascript]
55
references:
66
'<svg>': https://developer.mozilla.org/en-US/docs/Web/SVG/Element/svg
7+
'<details>': https://developer.mozilla.org/en-US/docs/Web/HTML/Element/details
8+
'<summary>': https://developer.mozilla.org/en-US/docs/Web/HTML/Element/summary
Lines changed: 118 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,118 @@
1+
---
2+
title: Creating tabbed content without JavaScript
3+
shortTitle: Details tabbed content
4+
language: css
5+
tags: [interactivity]
6+
cover: flower-portrait-6
7+
excerpt: Leverage modern HTML and CSS capabilities to create a tabbed content component without JavaScript.
8+
listed: true
9+
dateModified: 2025-05-26
10+
---
11+
12+
A few weeks back, I was working on a **tabbed content component** and wondered if I could leverage the `<details>` HTML element to create a more semantic and accessible solution. After some experimentation, I found that it was indeed possible, but there's a small caveat: it needs the `::details-content` pseudo-element to work properly.
13+
14+
<baseline-support featureId="details-content">
15+
</baseline-support>
16+
17+
As you may be aware by now, the `<details>` element creates collapsable sections of content. Adding the same `name` attribute to multiple `<details>` elements allows you to create an accordion-style component. We can build on top of that to create a tabbed content component.
18+
19+
```html
20+
<div class="tabs-container">
21+
<details name="tabs" open>
22+
<summary>First tab</summary>
23+
<div><p>First tab content</p></div>
24+
</details>
25+
<details name="tabs">
26+
<summary>Second tab</summary>
27+
<div><p>Second tab content</p></div>
28+
</details>
29+
</div>
30+
```
31+
32+
@[Quick refresher](/html/s/details-accordion)
33+
34+
In order for this trick to work, we'll have to wrap all of our elements in a `<div>` or similar **container** and make it a **grid**. We'll then set up our grid to be `N x 2`, where `N` is the **number of tabs** we want.
35+
36+
```css
37+
.tabs-container {
38+
position: relative;
39+
display: grid;
40+
grid-template-rows: auto 1fr;
41+
/* For 2 tabs, adjust to your needs */
42+
grid-template-columns: repeat(2, auto);
43+
}
44+
```
45+
46+
The **first row** will contain our tab _handles_ (the `<summary>` elements), and the **second row** will contain the content of each tab. We'll use the appropriate `grid-row` and `grid-column` properties to set these up correctly.
47+
48+
```css
49+
.tabs-container > details > summary {
50+
grid-row: 1;
51+
}
52+
53+
.tabs-container > details > div {
54+
grid-column: 1 / -1;
55+
}
56+
```
57+
58+
In order for the open tab to display correctly, we'll need to set the `<details>` element, along with the `::details-content` pseudo-element to `display: contents`. This essentially means that **the element will not generate a box**, but its children will be displayed as if they were direct children of the parent element. This allows us to keep the semantic structure of the HTML while still achieving the desired layout.
59+
60+
```css
61+
.tabs-container > details {
62+
display: contents;
63+
}
64+
65+
.tabs-container > details[open]::details-content {
66+
display: contents;
67+
}
68+
```
69+
70+
And that's pretty much all that's needed. Slap a few styles to make it pretty and you've got yourself a **JavaScript-free** tabbed content component.
71+
72+
https://codepen.io/chalarangelo/pen/JoodqXo
73+
74+
```html
75+
<div class="tabs-container">
76+
<details name="tabs" open>
77+
<summary>First tab</summary>
78+
<div><p>First tab content</p></div>
79+
</details>
80+
<details name="tabs">
81+
<summary>Second tab</summary>
82+
<div><p>Second tab content</p></div>
83+
</details>
84+
</div>
85+
```
86+
87+
```css
88+
.tabs-container {
89+
position: relative;
90+
display: grid;
91+
grid-template-rows: auto 1fr;
92+
grid-template-columns: repeat(2, auto);
93+
}
94+
95+
.tabs-container > details {
96+
display: contents;
97+
}
98+
99+
.tabs-container > details > summary {
100+
display: flex;
101+
justify-content: center;
102+
grid-row: 1;
103+
}
104+
105+
/* Hides the ::marker pseudo-element */
106+
.tabs-container > details > summary::marker {
107+
display: none;
108+
content: "";
109+
}
110+
111+
.tabs-container > details > div {
112+
grid-column: 1 / -1;
113+
}
114+
115+
.tabs-container > details[open]::details-content {
116+
display: contents;
117+
}
118+
```

0 commit comments

Comments
 (0)