While this tutorial has content that we believe is of great benefit to our community, we have not yet tested or edited it to ensure you have an error-free learning experience. It's on our list, and we're working on it! You can help us out by using the "report an issue" button at the bottom of the tutorial.

Collapsible widgets are a popular way to create sections of content that can contract and expand. There are a ton of different implementations out there. Here, thanks to checkbox input elements, label elements and the :checked pseudo-selector, we’ll be able create such widget without the need for extra JavaScript.

Here’s what our collapsible looks like:

See the Pen KKzWqVX by alligatorio (@alligatorio) on CodePen.

And here’s the HTML markup for it:

<div class="wrap-collabsible"> <input id="collapsible" class="toggle" type="checkbox"> <label for="collapsible" class="lbl-toggle">More Info</label> <div class="collapsible-content"> <div class="content-inner"> <p> QUnit is by calling one of the object that are embedded in JavaScript, and faster JavaScript program could also used with its elegant, well documented, and functional programming using JS, HTML pages Modernizr is a popular browsers without plug-ins. Test-Driven Development. </p> </div> </div> </div>

If you want a collapsible to be opened by default, simply set the checked attribute on the checkbox:

<input id="collapsible2" class="toggle" type="checkbox" checked >

See the Pen qBZrjqG by alligatorio (@alligatorio) on CodePen.

Note that each label should be associated with the correct checkbox, so each checkbox element needs a unique id and each label’s for attribute should point to the corresponding checkbox’s id.

Styling Our Collapsible

Let’s breakdown the styles bit by bit…

First we set the checkbox element to display: none . The checkbox will be invisible and its label will be used instead to check or uncheck it. Later, you’ll see that we’ll use the CSS :checked pseudo-selector to style things differently when the hidden checkbox is checked:

input[type='checkbox'] { display: none; }

Next, we style our default label. Here nothing really special is going on, except for the fact that we make our label display as a block element with display: block :

.lbl-toggle { display: block; font-weight: bold; font-family: monospace; font-size: 1.2rem; text-transform: uppercase; text-align: center; padding: 1rem; color: #A77B0E; background: #FAE042; cursor: pointer; border-radius: 7px; transition: all 0.25s ease-out; } .lbl-toggle:hover { color: #7C5A0B; }

For the small arrow, some clever use of borders makes it easy to create the triangle shape:

.lbl-toggle::before { content: ' '; display: inline-block; border-top: 5px solid transparent; border-bottom: 5px solid transparent; border-left: 5px solid currentColor; vertical-align: middle; margin-right: .7rem; transform: translateY(-2px); transition: transform .2s ease-out; }

Refer to this post from CSS-Tricks for all your CSS triangle needs.

You may have noticed also that we made use of the currentColor built-in variable so that our triangle is the same color as our label’s text.

Let’s also give some basic styles to the inner content:

.collapsible-content .content-inner { background: rgba(250, 224, 66, .2); border-bottom: 1px solid rgba(250, 224, 66, .45); border-bottom-left-radius: 7px; border-bottom-right-radius: 7px; padding: .5rem 1rem; }

Now we can start with the interesting part. By default, the collapsible-content div will have a max-height value of 0px, making it completely hidden:

.collapsible-content { max-height: 0px; overflow: hidden; transition: max-height .25s ease-in-out; }

When a collapsible’s checkbox gets checked behind the scenes by clicking its label, we’ll set the content div to a high-enough max-height value so that it can grow to display all its internal content.

Instead of trying to figure out a good height manually, you can also just make use of viewport units with something like 100vh. Using something like 100% would also work, but you’d lose the ability to use transitions. Note that you’ll still probably want to using something like 100% if you think the content in the collapsible could be taller than the viewport.

We make use of the adjacent sibling selector (+) to select our content div when the checkbox is checked:

.toggle :checked + .lbl-toggle + .collapsible-content { max-height: 100vh; }

We use max-height instead of height because we want to avoid using a hard-coded height and want to be able to place content of arbitrary height into our collapsibles.

And now we do something really similar using the adjacent sibling selector to rotate our little triangle shape when the collapsible is expanded and to adjust the bottom right and border left radius of our label:

.toggle:checked + .lbl-toggle::before { transform: rotate(90deg) translateX(-3px); } .toggle:checked + .lbl-toggle { border-bottom-right-radius: 0; border-bottom-left-radius: 0; }

And there you have it! A pretty straightforward way to create a collapsible section without using any scripting at all.

A Note on Accessibility

As it is now, our collapsible widget is not really accessible. We’ll have to add a touch of JavaScript to make it accessible. I know, I know, the whole thing is supposed to be implemented using zero JavaScript. What can I say!

Accessibility technology is constantly improving, leave a comment below if there is a better way to make this accessible.

In the following script we select all the toggle labels and listen for keydown events. If the pressed key is either the enter or the spacebar keys, we trigger a click on the label.

let myLabels = document.querySelectorAll('.lbl-toggle'); Array.from(myLabels).forEach(label => { label.addEventListener('keydown', e => { // 32 === spacebar // 13 === enter if (e.which === 32 || e.which === 13) { e.preventDefault(); label.click(); }; }); });

To make the label focusable, we add tabindex="0" to it:

<label for="collapsible3" class="lbl-toggle" tabindex="0" >With A11y</label>

See the Pen OJNpgpb by alligatorio (@alligatorio) on CodePen.

All Styles

Here are the full set styles at once, for your reference:

.wrap-collabsible { margin-bottom: 1.2rem 0; } input[type='checkbox'] { display: none; } .lbl-toggle { display: block; font-weight: bold; font-family: monospace; font-size: 1.2rem; text-transform: uppercase; text-align: center; padding: 1rem; color: #A77B0E; background: #FAE042; cursor: pointer; border-radius: 7px; transition: all 0.25s ease-out; } .lbl-toggle:hover { color: #7C5A0B; } .lbl-toggle::before { content: ' '; display: inline-block; border-top: 5px solid transparent; border-bottom: 5px solid transparent; border-left: 5px solid currentColor; vertical-align: middle; margin-right: .7rem; transform: translateY(-2px); transition: transform .2s ease-out; } .toggle:checked + .lbl-toggle::before { transform: rotate(90deg) translateX(-3px); } .collapsible-content { max-height: 0px; overflow: hidden; transition: max-height .25s ease-in-out; } .toggle:checked + .lbl-toggle + .collapsible-content { max-height: 100vh; } .toggle:checked + .lbl-toggle { border-bottom-right-radius: 0; border-bottom-left-radius: 0; } .collapsible-content .content-inner { background: rgba(250, 224, 66, .2); border-bottom: 1px solid rgba(250, 224, 66, .45); border-bottom-left-radius: 7px; border-bottom-right-radius: 7px; padding: .5rem 1rem; }

🌈 Enjoy your fancy almost-CSS-only collapsible!