The problem with Oxygen's built-in accordion

If you've spent time with bde-accordion in Oxygen Builder 6, you've probably noticed it works perfectly well for basic text and images. But try putting a contact form inside one, or content that loads dynamically, and things start to break.

The reason is how Oxygen calculates height. It uses inline CSS to animate the open/close transition, measuring the content height when the accordion opens, then setting that value directly on the element. For static content, this is fine. But if the content changes height after it loads (as forms often do when scripts initialise, or when validation messages appear), the calculated height is wrong, and you end up with content clipped or visually broken.

On a recent project, we needed accordions containing a Gravity Form, dynamic content pulled from ACF relationship fields, and in some cases both at once. The built-in accordion wasn't going to cut it.

Enter: native HTML <details> and <summary>

The <details> and <summary> elements are built right into HTML with no JavaScript required to open and close them. The browser handles everything natively.

<details>
  <summary>Click to expand</summary>
  <p>Your content goes here.</p>
</details>

When a user clicks the <summary>, the browser toggles a built-in open attribute on the <details> element. No height calculations, no inline styles. It just works. Dynamic content is handled gracefully, because there's no fixed height to get wrong.

How to add this in Oxygen Builder 6

Oxygen doesn't have a native <details> element in the builder panel, but that's easily solved with a Code Block.

  1. Add a Code Block element where you want the accordion to appear.
  2. In the PHP/HTML tab, paste your <details> structure.
  3. Style it using Oxygen's CSS editor, or add a Stylesheet element.

Here's a fuller example with multiple items:

<div class="accordion-group">

  <details class="accordion-item">
    <summary class="accordion-trigger">What services do you offer?</summary>
    <div class="accordion-content">
      <p>We offer a range of services including...</p>
    </div>
  </details>

  <details class="accordion-item">
    <summary class="accordion-trigger">How do I get in touch?</summary>
    <div class="accordion-content">
      <p>You can reach us via the contact form below.</p>
    </div>
  </details>

</div>

The wrapper <div> and class names aren't strictly necessary, but they give you clean hooks to style against.

Styling your accordion

Out of the box, <details> and <summary> are pretty plain. Here's a starter CSS set that removes the default browser triangle and gives you something to build on:

.accordion-item {
  border-bottom: 1px solid #e0e0e0;
}

.accordion-trigger {
  list-style: none; /* removes the default triangle */
  cursor: pointer;
  padding: 1rem 0;
  font-weight: 600;
  display: flex;
  justify-content: space-between;
  align-items: center;
}

.accordion-trigger::-webkit-details-marker {
  display: none; /* removes triangle in WebKit browsers */
}

.accordion-trigger::after {
  content: '+';
  font-size: 1.25rem;
}

details[open] .accordion-trigger::after {
  content: '−';
}

.accordion-content {
  padding-bottom: 1rem;
}

The details[open] selector is your friend here: it applies whenever the accordion is expanded, so you can style both states cleanly without any JavaScript.

Adding JavaScript for extra control

For most use cases, <details> and <summary> need zero JavaScript. But two situations benefit from a small script:

Closing other items when one opens

document.querySelectorAll('details.accordion-item').forEach(function (detail) {
  detail.addEventListener('toggle', function () {
    if (detail.open) {
      document.querySelectorAll('details.accordion-item').forEach(function (other) {
        if (other !== detail) other.removeAttribute('open');
      });
    }
  });
});

Add this via Oxygen's Code Block (JS tab) or in your footer scripts.

Reinitialising a form inside the accordion

If you're embedding Gravity Forms, you'll need to tell it to reinitialise when the accordion opens. Otherwise the form scripts haven't set up correctly against the visible DOM. A toggle listener handles this:

document.querySelectorAll('details.accordion-item').forEach(function (detail) {
  detail.addEventListener('toggle', function () {
    if (detail.open) {
      jQuery(document).trigger('gform_post_render', [formId, 1]);
    }
  });
});

Replace formId with the ID of your specific Gravity Form.

When to stick with the built-in accordion

bde-accordion isn't worthless. For simple static content it's quick to drop in and easy to configure within the builder UI. Reach for <details> and <summary> when:

  • The accordion contains a form
  • Content changes after the page loads (ACF dynamic fields, etc.)
  • You want full control over the HTML structure
  • You need reliable behaviour without fighting inline styles

Final thoughts

Native HTML elements tend to age well. <details> and <summary> are supported across all modern browsers and have been for years. Building on them rather than around Oxygen's height-calculation workaround means less JavaScript to maintain and fewer moving parts to break.

If you're building charity or nonprofit websites on WordPress with Oxygen Builder 6, keep an eye on the Sea Brand blog for more practical guides from real projects.