Accordions

Customizable stylised <details> disclosure elements designed to be used with the name attribute to create native HTML accordions or on single elements. Disabled by default, enable with $enable-accordions: true; in the configuration.scss document.

Accordion component (anchor)

Currently the technique still requires a JS polyfill script to work on Firefox (see further below).

Summary

Body text

Summary

Body text

Summary

Body text

Example HTML

The unique name attributes on each associates the individual details elements as a single accordion, the .accordion on the wrapper element styles the elements as displayed above. The role attribute is included to associate the accordions together as a group for accessibility but not required for functionality.

The .details-body wrapper is required to contain and style the details inner content but will eventually become redudant if the pseudo-element ::details-content becomes widely available.

<div role="group" class="accordion">
  <details name="accordion" open>
    <summary>Summary</summary>
    <div class="details-body">
      <p>Body text</p>
    </div>
  </details>
  <details name="accordion">
    <summary>Summary</summary>
    <div class="details-body">
      <p>Body text</p>
    </div>
  </details>
  <details name="accordion">
    <summary>Summary</summary>
      <div class="details-body">
    <p>Body text</p>
  </div>
  </details>
</div>

Single disclosure element (anchor)

A utility class for applying the accordion styles to single details disclosure elements.

Summary

Body text

Example HTML
<details class="details" name="nav-menu">
  <summary>Summary</summary>
  <div class="details-body">
    <p>Body text</p>
  </div>
</details>

Single elements can also be used with the name attribute to create standalone accordion components.

Summary

Body text

Summary

Body text

Summary

Body text

Example HTML

Note: For demo purposes the .mb-1 utility included below overrides the margin below each <details> element of 1rem provided with the foundation styles.

<details name="accordion-floating" class="details mb-1" open>
  <summary>Summary</summary>
  <div class="details-body">
    <p>Body text</p>
  </div>
</details>
<details name="accordion-floating" class="details mb-1">
  <summary>Summary</summary>
  <div class="details-body">
    <p>Body text</p>
  </div>
</details>
<details name="accordion-floating" class="details">
  <summary>Summary</summary>
    <div class="details-body">
  <p>Body text</p>
</div>
</details>

Colors (anchor)

Each color has two modifiers classes that share the same values (e.g. .details-light and .accordion-light), either of these utilities can be included to apply the color to the accordions or individual details elements.

With $enable-theme-colors: true;

Summary light

Body text

Summary light

Body text

Summary light

Body text

Details light

Body text

Summary dark

Body text

Summary dark

Body text

Summary dark

Body text

Details dark

Body text

Example HTML
<div role="group" class="accordion accordion-light">
  <details name="accordion-light" open>
    <summary>Summary light</summary>
    <div class="details-body">
      <p>Body text</p>
    </div>
  </details>
  <details name="accordion-light">
    <summary>Summary light</summary>
    <div class="details-body">
      <p>Body text</p>
    </div>
  </details>
  <details name="accordion-light">
    <summary>Summary light</summary>
      <div class="details-body">
    <p>Body text</p>
  </div>
  </details>
</div>

<details class="details details-light">
  <summary>Details light</summary>
  <div class="details-body">
    <p>Body text</p>
  </div>
</details>

<div role="group" class="accordion accordion-dark">
  <details name="accordion-dark" open>
    <summary>Summary dark</summary>
    <div class="details-body">
      <p>Body text</p>
    </div>
  </details>
  <details name="accordion-dark">
    <summary>Summary dark</summary>
    <div class="details-body">
      <p>Body text</p>
    </div>
  </details>
  <details name="accordion-dark">
    <summary>Summary dark</summary>
    <div class="details-body">
      <p>Body text</p>
    </div>
  </details>
</div>

<details class="details details-dark">
  <summary>Details dark</summary>
  <div class="details-body">
    <p>Body text</p>
  </div>
</details>

With $enable-primary-colors: true;

Summary blue

Body text

Summary blue

Body text

Summary blue

Body text

Details blue

Body text

Summary red

Body text

Summary red

Body text

Summary red

Body text

Details red

Body text

Summary green

Body text

Summary green

Body text

Summary green

Body text

Details green

Body text

Summary orange

Body text

Summary orange

Body text

Summary orange

Body text

Details orange

Body text

Summary cyan

Body text

Summary cyan

Body text

Summary cyan

Body text

Details cyan

Body text

Example HTML
<div role="group" class="accordion accordion-blue">
  <details name="accordion-blue" open>
    <summary>Summary blue</summary>
    <div class="details-body">
      <p>Body text</p>
    </div>
  </details>
  <details name="accordion-blue">
    <summary>Summary blue</summary>
    <div class="details-body">
      <p>Body text</p>
    </div>
  </details>
  <details name="accordion-blue">
    <summary>Summary blue</summary>
    <div class="details-body">
      <p>Body text</p>
    </div>
  </details>
</div>

<details class="details details-blue mb-0">
  <summary>Details blue</summary>
  <div class="details-body">
    <p>Body text</p>
  </div>
</details>

<div role="group" class="accordion accordion-red">
  <details name="accordion-red" open>
    <summary>Summary red</summary>
    <div class="details-body">
      <p>Body text</p>
    </div>
  </details>
  <details name="accordion-red">
    <summary>Summary red</summary>
    <div class="details-body">
      <p>Body text</p>
    </div>
  </details>
  <details name="accordion-red">
    <summary>Summary red</summary>
    <div class="details-body">
      <p>Body text</p>
    </div>
  </details>
</div>

<details class="details details-red mb-0">
  <summary>Details red</summary>
  <div class="details-body">
    <p>Body text</p>
  </div>
</details>

<div role="group" class="accordion accordion-green">
  <details name="accordion-green" open>
    <summary>Summary green</summary>
    <div class="details-body">
      <p>Body text</p>
    </div>
  </details>
  <details name="accordion-green">
    <summary>Summary green</summary>
    <div class="details-body">
      <p>Body text</p>
    </div>
  </details>
  <details name="accordion-green">
    <summary>Summary green</summary>
    <div class="details-body">
      <p>Body text</p>
    </div>
  </details>
</div>

<details class="details details-green mb-0">
  <summary>Details green</summary>
  <div class="details-body">
    <p>Body text</p>
  </div>
</details>

<div role="group" class="accordion accordion-orange">
  <details name="accordion-orange" open>
    <summary>Summary orange</summary>
    <div class="details-body">
      <p>Body text</p>
    </div>
  </details>
  <details name="accordion-orange">
    <summary>Summary orange</summary>
    <div class="details-body">
      <p>Body text</p>
    </div>
  </details>
  <details name="accordion-orange">
    <summary>Summary orange</summary>
    <div class="details-body">
      <p>Body text</p>
    </div>
  </details>
</div>

<details class="details details-orange mb-0">
  <summary>Details orange</summary>
  <div class="details-body">
    <p>Body text</p>
  </div>
</details>

<div role="group" class="accordion accordion-cyan">
  <details name="accordion-cyan" open>
    <summary>Summary cyan</summary>
    <div class="details-body">
      <p>Body text</p>
    </div>
  </details>
  <details name="accordion-cyan">
    <summary>Summary cyan</summary>
    <div class="details-body">
      <p>Body text</p>
    </div>
  </details>
  <details name="accordion-cyan">
    <summary>Summary cyan</summary>
    <div class="details-body">
      <p>Body text</p>
    </div>
  </details>
</div>

<details class="details details-cyan mb-0">
  <summary>Details cyan</summary>
  <div class="details-body">
    <p>Body text</p>
  </div>
</details>

Firefox polyfill JS (anchor)

The accordions created using the name attibute requires no scripting with the current exception being Firefox which still requires a polyfill, the example below is shared in the Themalize repository ([assets/js/accordion.js]).

View script
//  --------------------------------------------------------------
//  Exclusive accordion polyfill
//  https://codepen.io/web-dot-dev/pen/BaMbKyM
//  When a <details> element with a [name] opens, this code finds
//  the other open ones with that [name] and closes them manually.
//  --------------------------------------------------------------

document.querySelectorAll("details[name]").forEach(($details) => {
  $details.addEventListener("toggle", (e) => {
    const name = $details.getAttribute("name");

    if (e.newState == "open") {
      document
        .querySelectorAll(`details[name=${name}][open]`)
        .forEach(($openDetails) => {
          if (!($openDetails == $details)) {
            $openDetails.removeAttribute("open");
          }
        });
    }
  });
});

Customize (anchor)

The accordions core property values are provided as CSS variables that can be used to customize the styles inline. The values are compiled from Sass variables that can be customized in the properties.scss document when compiling.

Property values
$summary-txt:         var(--text) !default;
$summary-bg:          var(--surf-1) !default;
$summary-ico:         var(--summary-txt) !default;
$details-py:          0.5rem !default;
$details-px:          0.75rem !default;
$details-bd-color:    var(--surf-3) !default;
$details-bd-width:    1px !default;
$details-radius:      0.125em !default;

The styles are regular CSS that can be customized in the _accordions.scss document within the [styles/components] directory. The Sass @if rules control compiling depending on settings in the configuration.scss document.

Styles
@if $enable-accordions {

:where(.details, .accordion) {
  @if $enable-caret-down-svg and $enable-caret-up-svg {
    --details-open: var(--caret-down);
    --details-closed: var(--caret-up);
  }
  @else {
    --details-open: #{$caret-down};
    --details-closed: #{$caret-up};
  }
  max-inline-size: var(--details-max-width);
}

:where(.accordion details) {
  margin-block-end: 0;
}

// Open and close icons.
:where(.details summary, .accordion summary):after {
  --ico: var(--summary-ico);
  --svg: var(--details-open);
  @extend %icon-mask;
  float: right;
  margin-block-start: calc(var(--fs) / 4);
  margin-inline-start: 1rem;
}

:where(.details[open] summary, .accordion details[open] summary):after {
  --svg: var(--details-closed);
}

:where(.details summary, .accordion summary) {
  --ico: var(--summary-ico);
  color: var(--summary-txt);
  font-weight: 600;
  list-style-type: "";
  padding-block: var(--details-py);
  padding-inline: var(--details-px);
  border: var(--details-bd-width) solid var(--details-bd-color);
  border-radius: var(--details-radius);
  background-color: var(--summary-bg);
}

.details summary::-webkit-details-marker { 
  display: none;
}

.accordion summary::-webkit-details-marker { 
  display: none;
}

:where(.accordion summary) {
  border-radius: 0; 
}

:where(.accordion details:not(:first-child) summary) {
  border-block-start: none;
}

:where(.accordion details:first-child summary) {
  border-start-start-radius: var(--details-radius);
  border-start-end-radius: var(--details-radius);
}

:where(.accordion details:last-child summary) {
  border-end-start-radius: var(--details-radius);
  border-end-end-radius: var(--details-radius);
}

:where(.details[open] summary, .accordion [open] summary) {
  margin-block-end: 0;
  border-block-end: var(--details-bd-width) solid var(--details-bd-color);
  border-end-start-radius: 0;
  border-end-end-radius: 0;
}

:where(.accordion details[open]:last-child summary) {
  border-end-start-radius: 0;
  border-end-end-radius: 0;
}

// Body
:where(.details-body, .details-body-code) {
  padding-block: var(--details-py);
  padding-inline: var(--details-px);
  border: var(--details-bd-width) solid var(--details-bd-color);
  border-block-start: none;
  border-radius: var(--details-radius);
  border-start-start-radius: 0;
  border-start-end-radius: 0;
}

:where(.accordion .details-body) {
  border-radius: 0;
}

:where(.accordion details:last-child[open] .details-body) {
  border-end-start-radius: var(--details-radius);
  border-end-end-radius: var(--details-radius);
}

:where(.details-body :last-child) {
  --mb: 0;
}

:where(.details-body-code) {
  --details-py: 0;
  --details-px: 0;
}

:where(.details-body-code) pre {
  border: none;
  margin-block-end: 0;
}

@if $enable-theme-colors {

.details-light, .accordion-light {
  --summary-txt: #000;
  --summary-ico: #000;
  --summary-bg: var(--surf-1-light);
  --details-bd-color: var(--surf-3-light);
}

.details-dark, .accordion-dark {
  --summary-txt: #fff;
  --summary-ico: #fff;
  --summary-bg: var(--surf-1-dark);
  --details-bd-color: var(--surf-3-dark);
}

} // END [if/theme-colors]

@if $enable-primary-colors {

.details-blue, .accordion-blue {
  --summary-txt: #fff;
  --summary-ico: #fff;
  --summary-bg: var(--blue);
  --details-bd-color: var(--blue-lighter);
}

.details-red, .accordion-red {
  --summary-txt: #fff;
  --summary-ico: #fff;
  --summary-bg: var(--red);
  --details-bd-color: var(--red-lighter);
}

.details-green, .accordion-green {
  --summary-txt: #fff;
  --summary-ico: #fff;
  --summary-bg: var(--green);
  --details-bd-color: var(--green-lighter);
}

.details-orange, .accordion-orange {
  --summary-txt: #000;
  --summary-ico: #000;
  --summary-bg: var(--orange);
  --details-bd-color: var(--orange-darker);
}

.details-cyan, .accordion-cyan {
  --summary-txt: #000;
  --summary-ico: #000;
  --summary-bg: var(--cyan);
  --details-bd-color: var(--cyan-darker);
}

} // END [@if/primary-colors]

} // END [@if/details]