Today's resource is a handy accordion menu with support for groups/subitems. It works with CSS only, using the :checked
pseudo-class selector on the checkboxes input elements. However we included a version with JavaScript as well, in case you prefer a subtle animation compared to the instant default effect. Your call!
The first user case I can think of for this resources is a "layer organizer". Think of Sublime Text sidebar, or Photoshop layer window. Anyway, I'm sure you'll find a use for this new snippet to store in your arsenal ;)
- ⭐️ Icons: Nucleo, icon organizer & icon library
👋 A new version of this component is available. Download now →.
Creating the structure
The HTML structure is pretty simple: the accordion is an unordered list. If a list item contains subitems, then we insert an input[type=checkbox]
and its label. Also, we add the .cd-accordion__item--has-children
class to the list item. All "standard" list items contain just an anchor tag.
<ul class="cd-accordion margin-top-lg margin-bottom-lg">
<li class="cd-accordion__item cd-accordion__item--has-children">
<input class="cd-accordion__input" type="checkbox" name ="group-1" id="group-1">
<label class="cd-accordion__label cd-accordion__label--icon-folder" for="group-1"><span>Group 1</span></label>
<ul class="cd-accordion__sub cd-accordion__sub--l1">
<li class="cd-accordion__item cd-accordion__item--has-children">
<input class="cd-accordion__input" type="checkbox" name ="sub-group-1" id="sub-group-1">
<label class="cd-accordion__label cd-accordion__label--icon-folder" for="sub-group-1"><span>Sub Group 1</span></label>
<ul class="cd-accordion__sub cd-accordion__sub--l2">
<li class="cd-accordion__item"><a class="cd-accordion__label cd-accordion__label--icon-img" href="#0"><span>Image</span></a></li>
<li class="cd-accordion__item"><a class="cd-accordion__label cd-accordion__label--icon-img" href="#0"><span>Image</span></a></li>
<li class="cd-accordion__item"><a class="cd-accordion__label cd-accordion__label--icon-img" href="#0"><span>Image</span></a></li>
</ul>
</li>
<li class="cd-accordion__item"><a class="cd-accordion__label cd-accordion__label--icon-img" href="#0"><span>Image</span></a></li>
<li class="cd-accordion__item"><a class="cd-accordion__label cd-accordion__label--icon-img" href="#0"><span>Image</span></a></li>
</ul>
</li>
<li class="cd-accordion__item cd-accordion__item--has-children">
<a class="cd-accordion__label cd-accordion__label--icon-img" href="#0"><span>Image</span></a>
</li>
<li class="cd-accordion__item cd-accordion__item--has-children">
<a class="cd-accordion__label cd-accordion__label--icon-img" href="#0"><span>Image</span></a>
</li>
</ul> <!-- cd-accordion -->
Adding style
We use a smart (and quite standard nowadays) technique to detect the click and show sub content with CSS only: by including a checkbox input element, we can use the :checked
pseudo-class and the general sibling selector (div ~ div) to change the display mode of the sub <ul>
element from "none" to "block".
Step by step: first of all, we have to make sure that the checkbox input element covers the entire list item that contains subitems. Put in other words: we need to create a custom checkbox.
So, firstly, you need to make sure that when you click on the label, the checkbox is checked/unchecked as well. This is achieved by using the "for" attribute inside the label (label "for" attribute = input "name" and "id" attributes. See html section above). This way you can simply hide the input element and work with the label instead.
.cd-accordion__input { // hide native checkbox
position: absolute;
opacity: 0;
}
.cd-accordion__label {
position: relative;
display: flex;
align-items: center;
padding: var(--space-sm) var(--space-md);
background: var(--cd-color-1);
box-shadow: inset 0 -1px lightness(var(--cd-color-1), 1.2);
color: var(--color-white);
}
Now notice in the HTML structure that input, label and the unordered list (that we make visible on click) are siblings. By using the :checked
pseudo-class, you can set the following process in motion: when the checkbox input is checked (click on label), take the .cd-accordion__sub
sibling element and change its display value from "none" to "block":
.cd-accordion__sub {
display: none; // by default hide all sub menus
}
.cd-accordion__input:checked ~ .cd-accordion__sub { // show children when item is checked
display: block;
}
If you want to gently animate the opening phase, make sure to add the .cd-accordion--animated
class to the main .cd-accordion
element.