Creating Modern Accordion Components with CSS and HTML only
Tags: css, a11y, webdev, html
Published: 2024-02-21 09:32:11

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](https://sugar-css.com/doc/components/accordion).*

---

## 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:

{% codepen https://codepen.io/rezi-the-lessful/pen/eYXoyBp %}

## 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:

```css
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:

```css
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]`:

```css
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:

```css
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 

{% codepen https://codepen.io/rezi-the-lessful/pen/MWxRbyo %}

Additional styles like colours and spacings can make it more vivid

{% codepen https://codepen.io/rezi-the-lessful/pen/GReLaJL %}

---

## 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.