Welcome to the first instalment of a series dedicated to crafting common components using only modern CSS and HTML.
Note: I am the author of Sugar.css, a minimalistic CSS Framework built with the latest CSS. You can explore a more advanced implementation of a similar accordion on Sugar.css.
Assignment
What are the essential features of a proper Accordion?
- Toggle content on user input or programmatically
- Accessibility (toggle on Enter and Space)
- Disable access to accordion content (by keyboard) when the accordion is collapsed
- Stacking multiple accordions after each other
- Auto close other accordions in the group when one is opened
Toggling Content
Gone are the days when the only way to toggle styles permanently was through a label with a hidden checkbox. For the past few years, we've been able to use a combination of details
and summary
HTML elements to achieve this. The details
element hides all its content by default, except for a summary
element if placed as a direct child. The summary
serves as a toggle button; if not present, the text details is added as a default toggle. By clicking the toggle, the rest of the hidden content is revealed. Let's observe the default behavior and design:
Accessibility
All accessibility features are built-in; the summary has a default tabindex and can be toggled by Space and Enter keys, so no additional work is needed here.
Disabling Access to Content When Collapsed
While this functionality should work out of the box, there's an exception with Safari. If the details
element is collapsed and contains focusable elements like input
or button
, tabbing in Safari will be consumed by those hidden elements. To ensure consistent accessibility across browsers, a simple JavaScript solution is required. The content is wrapped, and the inert
attribute needs to be set to the wrapper once the details
is collapsed.
Styling
Let's apply some CSS to enhance the appearance. First, we'll remove the original triangle indicator. This can be done differently in various browsers, but the following CSS accomplishes this:
summary::marker,
summary::-webkit-details-marker {
display: none;
}
summary {
list-style:none;
}
Next, we'll style the summary to resemble an accordion header and prepare it for a new chevron:
summary {
list-style: none;
display: flex;
gap: 1rem;
align-items: center;
justify-content: space-between;
cursor: pointer;
padding-block: var(--padding);
font-weight:bold;
}
details {
--padding: 0.75rem;
--border-width: 0.1rem;
--chevron-size: 0.8rem;
font-family: system-ui;
font-size: 1rem;
}
To implement the new chevron for the base accordion, we'll create a rotated box with just two borders. The state of the opened accordion is selected by details[open]
:
details summary:after {
content: '';
margin-inline-end: var(--padding);
width: var(--chevron-size);
height: var(--chevron-size);
border: solid currentColor;
border-width: 0 0 var(--border-width) var(--border-width);
transform: rotate(-45deg) translateY(-30%);
transition: transform 0.3s;
flex-shrink: 0;
}
details[open] summary:after {
transform: rotate(45deg);
}
Lastly, we'll add separators between accordions if there are more consecutive ones:
details:not(:last-of-type) {
margin-bottom: var(--padding);
padding-bottom: var(--padding);
border-bottom: var(--border-width) solid gray;
}
Grouping Accordions
Another useful feature of details
is its acceptance of a name
attribute. All details
with the same name behave as a group. When you open one, the others in the same group automatically close.
Check out the result
Additional styles like colours and spacings can make it more vivid
Conclusion
As demonstrated, details
and summary
are fully capable of replacing JavaScript-driven accordions. They make implementation easier and provide immediate accessibility (with the exception of Safari, which requires a workaround for a specific edge case).
However, there's one potential drawback: the lack of animation support. If animation is applied to collapsed content within details
, it runs only once when opened and cannot be rerun when opened next time. This limitation may need to be considered based on the specific design and functionality requirements of your project.
Next time we will check the dialog
element. See you soon.
Top comments (0)