Welcome to a tutorial on how to create a simple responsive accordion with HTML and CSS. Yes, you read that right, no Javascript is involved.
To create an accordion using HTML and CSS only:
- Create a “stack” of checkbox, label, and container.
<input id="check" type="checkbox">
<label for="check">Title</label>
<div id="content">Content</div>
- Hide the checkbox and content by default. Only show the content when the checkbox is checked.
#check, #content { display: none; }
#check:checked ~ #content { display : block; }
Yep, that’s all for the basic mechanics. Read on for a “nice example”!
TABLE OF CONTENTS
DOWNLOAD & DEMO
Here is the download link to the example code, so you don’t have to copy-paste everything.
EXAMPLE CODE DOWNLOAD
Click here to download | Example on CodePen
The example code is released under the MIT license, so feel free to build on top of it or use it in your own project.
SORRY FOR THE ADS...
But someone has to pay the bills, and sponsors are paying for it. I insist on not turning Code Boxx into a "paid scripts" business, and I don't "block people with Adblock". Every little bit of support helps.
Buy Me A Coffee Code Boxx eBooks
ACCORDION DEMO
HTML CSS ACCORDION
All right, let us now get into a slightly more detailed example of the HTML CSS accordion.
TUTORIAL VIDEO
PART 1) THE HTML
<!-- TAB 1 -->
<div class="a-tab">
<input id="tab-1" class="a-check" type="checkbox">
<label for="tab-1" class="a-label">Title 1</label>
<div class="a-content"><img src="pasta.webp"></div>
</div>
<!-- TAB 2 -->
<div class="a-tab">
<input id="tab-2" class="a-check" type="checkbox">
<label for="tab-2" class="a-label">Title 2</label>
<div class="a-content"><img src="pizza.webp"></div>
</div>
- As in the introduction, we only need to create a “stack” of checkbox, label, and container.
- The only difference here is that we wrap them in a
<div class="a-tab">
.
PART 2) BASIC MECHANICS
/* (A) HIDE CHECKBOX & CONTENT */
.a-check { display: none; }
.a-content { max-height: 0; overflow: hidden; }
/* (B) SHOW CONTENT ON CHECKED */
.a-check:checked ~ .a-content { max-height: 500px; overflow: auto; }
.a-content { transition: all 0.5s; }
This is a slightly different approach from the introduction snippet.
- We hide the checkbox with
display: none
as usual. - But hide the content with
max-height: 0
andoverflow: hidden
. - The reason is simple, we combine
max-height
withtransition
to give a nice “grow and shrink” animation.
PART 3) RESPONSIVE & COSMETICS
/* (C) COSMETICS */
/* (C1) WRAPPER */
.a-tab { max-width: 600px; }
/* (C2) LABEL */
.a-label {
display: block; width: 100%; padding: 10px;
font-weight: 700; cursor: pointer;
color: #fff; background: #2d5faf;
}
/* (C3) LABEL ARROW */
.a-label { position: relative; }
.a-label::after {
display: block; content: "\25b6";
position: absolute; right: 10px; top: 10px;
transition: all 0.4s;
}
.a-check:checked ~ label::after { transform: rotate(90deg); }
/* (C4) CONTENT */
.a-check:checked ~ .a-content {
padding: 10px;
background: #ccdef9;
}
/* (C5) ENTIRE PAGE */
img { width: 100%; }
* {
font-family: Arial, Helvetica, sans-serif;
box-sizing: border-box;
}
The rest are pretty much cosmetics. Feel free to change the font, colors, and dimensions.
EXTRAS
That’s all for this guide, and here is a small section on some extras that may be useful to you.
ONLY ONE TAB CAN OPEN AT A TIME
<!-- TAB 1 -->
<div class="a-tab">
<input id="tab-1" name="tab-group" class="a-check" type="radio" checked>
<label for="tab-1" class="a-label">Title 1</label>
<div class="a-content"><img src="pasta.webp"></div>
</div>
<!-- TAB 2 -->
<div class="a-tab">
<input id="tab-2" name="tab-group" class="a-check" type="radio">
<label for="tab-2" class="a-label">Title 2</label>
<div class="a-content"><img src="pizza.webp"></div>
</div>
Use radio buttons instead of checkboxes, and set them to the same name.
OPENING TABS “BY DEFAULT”
How do we set a tab to be opened by default? Simply set the checked attribute – <input type="checkbox" checked>
.
RADIO ACCORDION RESTRICTION
Well, as some may have already noticed. The default behavior in HTML is that one radio button will be selected at all times, and there is no way we can unselect without using Javascript. So yes, the “restriction” in the radio button accordion is that one tab will be opened at all times.
LINKS & REFERENCES
- Javascript Accordion – Code Boxx
INFOGRAPHIC CHEAT SHEET
THE END
Thank you for reading, we have come to the end of this guide. I hope that it has helped you to create a better website, and if you have anything to share with this guide, please feel free to comment below. Good luck and happy coding!
Thanks a lot for this. Saves so much time by just using radio or checkbox! You are a genius.
It might be a very stupid question but since i can´t code at all i´ll go ahead and ask.
How can I use this on wordpress? I thought about adding the CSS in additional css in the customizer and add the tab class to a paragraph in gutenberg, but I´m pretty sure that´s not going to work because there would be no connection between the title and the content and between the titles and content and the other titles and content… In other words I don´t know where to put the html on wordpress
https://wpshout.com/quick-guides/wordpress-gutenberg-html/
Hi W.S.,
Thank you for the code/tutorial! If I wanted to move the arrow pointer to the left, how do I account for the heading text?
I changed the (F) section “right: 10px” to “left:10px”, which got the arrow on the correct side I want it to show on, but I don’t know how to fix the overlap it has with my tab title text.
Thank you!
Sylvia
Just offset the label
.tab label { padding-left: 50px; }
Thanks again for this. It is great. I have noticed an odd quirk perhaps. For the radio – one at a time drop-downs there seems to be an issue with scrolling when viewing on small screens so that sometimes when you click on a tab, the browser scrolls too far and you have to manually scroll back up to read the contents of the tab. Here is what I did to replicate which might explain better:
1) Include lots of paragraphs of text in each drop-down.
2) Include a few paragraphs of text after the drop-down (that is, paragraphs under the drop-down)
3) Click Tab 1. It displays fine.
4) Scroll down to Tab 2 and click Tab 2. It displays fine.
5) Scroll down to Tab 3 and click Tab 3. The browser scrolls down too far and you have to scroll back up to view the start of the text in Tab 3.
This only occurs on small sized screens. This behaviour does not occur on larger screens. I am not sure what causes it. Maybe there is a limitation on the amount of content you can include in a tab maybe?
Well, you kind of already answered your own question. That is a browser behavior and that is just the way how it renders the HTML/CSS… More CSS probably won’t fix anything. I will limit the content, or use Javascript to listen to the
animationend
event, then scroll back up automatically.Okay, thanks very much again.