NavigationFree

Accordion Basic

Pure-CSS collapsible sections: smooth max-height animation, rotating chevron, multi-open by default or exclusive mode with a single parameter.

CSSJSInteractive
Contenu de la première section avec animation de hauteur fluide.
Deuxieme section avec du contenu different.
Troisieme et dernière section.
Hover or click the scene to interact

This effect is free — the Navigation category contains 36 effects total, including 4 free. Effect.Labs has 811 vanilla effects. Explore the category →

Usage examples

EffectLabs
Account
Billing
Team
Security
Account settings
Name Anthony D.
Email a.dubois@…
Edit profile
Plan Pro · 9,90 €/mois
Next renewal 01/09/2026
Newsletter Active
Updates Active

① Settings Panel — SaaS Dashboard

WhenWhen an account settings page shows multiple setting categories (Profile, Billing, Notifications, Security) inside a dashboard interface.
WhyThe accordion compartmentalizes settings without page navigation: users open only relevant sections, reducing cognitive load and keeping scroll short.
SettingsMode 'basic' (multiple sections open simultaneously), max-height: 300px for longer sections. Add class .accordion-single for the indigo border on the active item.
API Reference · Effects
GET /api/effects
Returns a paginated list of effects matching the given filters.
Maximum number of effects returned per page.
Default: 20 · Max : 100
Page number (1-indexed). Combined with limit for cursor-based pagination.limit pour la pagination.
Défaut : 1
Filter by category slug. Returns all categories if omitted.
Example: navigation, particles, loaders

② API Reference — Expandable Parameters

WhenIn a technical documentation page (API reference, integration guide) with dozens of parameters or properties to describe.
WhyThe accordion lets users scan headers quickly and open only the entries they need — keeping dense technical content manageable without pagination.
SettingsMode 'single' (one parameter open at a time), max-height: 400px for code examples, transition: max-height 0.3s.
Categories
Smooth height animation
Contenu de la section.
Accordion Basic
Expandable sections with smooth height animation.
CSS JS Interactive Free
17 effects in Navigation

③ Sidebar — Category Navigation

WhenIn the sidebar of a site (effect library, resource portal, e-commerce) to present categories and sub-entries without overloading vertical space.
WhyCollapsed categories save sidebar space and the height animation guides the eye toward revealed content, with no page jump or reload.
SettingsMode 'basic', max-height: 250px, background: rgba(255,255,255,0.03) on items to differentiate from the sidebar, subtle hover.

How it works

The open/close mechanism relies on the CSS max-height trick: each .accordion-content starts at max-height: 0; overflow: hidden. When the .active class is added to the parent item, the rule .accordion-item.active .accordion-content { max-height: 200px } kicks in and the browser interpolates between the two values via transition: max-height 0.4s. The pre-existing overflow: hidden clips content cleanly throughout the transition.

The chevron is an inline SVG animated by a single CSS rule: .accordion-item.active .accordion-icon { transform: rotate(180deg) } with transition: transform 0.3s. The .accordion-header button gets a subtle background fade on hover (transition: background 0.3s) — both transitions are independent and composable.

The toggleAccordion(header, type) function is global (not wrapped in an IIFE), called directly from the onclick attribute of each button. It walks up to the item (header.parentElement) then to the accordion (.parentElement). In 'single' mode, it first removes .active from all other items before toggling the current one — only one section stays open. In 'basic' mode, it simply toggles the item without touching neighbors.

The .accordion-single CSS variant is an optional layer: adding that class to .accordion gives each item an indigo border (rgba(99,102,241,0.2)) and a glowing box-shadow on the active item. No extra JS required — just a class change in HTML.

Accessibility

  • prefers-reduced-motion not implemented: the max-height and transform transitions run regardless of system preference. Add @media (prefers-reduced-motion: reduce) { .accordion-content, .accordion-icon { transition: none; } } to fix.
  • aria-expanded missing: buttons do not expose their open/closed state to screen readers. For WCAG 4.1.2 compliance, add aria-expanded="false" by default and toggle it to true in toggleAccordion.
  • Keyboard: <button> elements are natively focusable and activatable via Space / Enter — no extra JS required.
  • Contrast: white text (#ffffff) on a dark background (rgba(255,255,255,0.05)) — ratio above 7:1, WCAG AA and AAA compliant.
  • Inline onclick: event handlers are on native <button> elements — accessible without CSS and in the default tab order.

Browser compatibility

Relies only on CSS transitions (max-height, transform) and class manipulation — available since 2013.

Chrome 49+✓ Full
Firefox 44+✓ Full
Safari 9+✓ Full
Edge 15+✓ Full
Mobile iOS✓ Full
Android Chrome✓ Full

Without JavaScript, buttons are inactive and sections stay in their initial state (first one pre-opened via the <code>.active</code> class in HTML). No fatal JS errors.

The code

Copy the three blocks into your page. No dependencies.

HTML
<div class="component-demo">
  <div class="accordion" id="accordionBasic">
    <div class="accordion-item active">
      <button class="accordion-header" onclick="toggleAccordion(this, 'basic')">
        Section 1
        <svg class="accordion-icon" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
          <path d="M6 9l6 6 6-6">
          </path>
        </svg>
      </button>
      <div class="accordion-content">
        <div class="accordion-body">
          Contenu de la première section avec animation de hauteur fluide.
        </div>
      </div>
    </div>
    <div class="accordion-item">
      <button class="accordion-header" onclick="toggleAccordion(this, 'basic')">
        Section 2
        <svg class="accordion-icon" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
          <path d="M6 9l6 6 6-6">
          </path>
        </svg>
      </button>
      <div class="accordion-content">
        <div class="accordion-body">
          Deuxieme section avec du contenu different.
        </div>
      </div>
    </div>
    <div class="accordion-item">
      <button class="accordion-header" onclick="toggleAccordion(this, 'basic')">
        Section 3
        <svg class="accordion-icon" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
          <path d="M6 9l6 6 6-6">
          </path>
        </svg>
      </button>
      <div class="accordion-content">
        <div class="accordion-body">
          Troisieme et dernière section.
        </div>
      </div>
    </div>
  </div>
</div>
CSS
.component-demo  {
   width: 100%;
   min-height: 200px;
   display: flex;
   flex-direction: column;
   align-items: center;
   justify-content: center;
   gap: 12px;
   }

.accordion  {
   width: 100%;
   max-width: 350px;
   }

.accordion-item  {
   background: rgba(255, 255, 255, 0.05);
   border-radius: 8px;
   margin-bottom: 8px;
   overflow: hidden;
   }

.accordion-header  {
   width: 100%;
   padding: 16px 20px;
   background: transparent;
   border-width: medium;
   border-style: none;
   border-color: currentcolor;
   border-image: initial;
   color: white;
   font-size: 0.95rem;
   font-weight: 500;
   font-family: inherit;
   display: flex;
   justify-content: space-between;
   align-items: center;
   cursor: pointer;
   transition: background 0.3s;
   }

.accordion-header:hover  {
   background: rgba(255, 255, 255, 0.05);
   }

.accordion-icon  {
   transition: transform 0.3s;
   }

.accordion-item.active .accordion-icon  {
   transform: rotate(180deg);
   }

.accordion-content  {
   max-height: 0px;
   overflow: hidden;
   transition: max-height 0.4s, padding 0.3s;
   }

.accordion-item.active .accordion-content  {
   max-height: 200px;
   }

.accordion-body  {
   padding: 0px 20px 16px;
   color: rgba(255, 255, 255, 0.6);
   font-size: 0.9rem;
   line-height: 1.6;
   }

.accordion-single .accordion-item  {
   border: 1px solid rgba(99, 102, 241, 0.2);
   }

.accordion-single .accordion-item.active  {
   border-color: rgba(99, 102, 241, 0.5);
   box-shadow: rgba(99, 102, 241, 0.15) 0px 4px 20px;
   }

.modal-overlay.active  {
   opacity: 1;
   visibility: visible;
   }

.modal.active  {
   transform: translateX(-50%) translateY(0px);
   }

.customizer-toggle.active  {
   transform: rotate(180deg);
   }

.customizer-overlay.active  {
   opacity: 1;
   visibility: visible;
   }

.customizer-panel.active  {
   right: 0px;
   }

.bg-option.active  {
   border-color: var(--primary, #6366f1);
   box-shadow: rgba(99, 102, 241, 0.3) 0px 0px 0px 2px;
   }

.font-option.active  {
   background: rgba(99, 102, 241, 0.1);
   border-color: var(--primary, #6366f1);
   }

.option-btn.active  {
   background: rgba(99, 102, 241, 0.15);
   border-color: var(--primary, #6366f1);
   color: var(--primary, #6366f1);
   }

.demo-card:hover .favorite-btn, .category-card:hover .favorite-btn, .favorite-btn.active  {
   opacity: 1;
   }

.favorite-btn.active  {
   color: rgb(251, 191, 36);
   }

.code-panel-overlay.active  {
   opacity: 1;
   visibility: visible;
   }

.code-panel.active  {
   opacity: 1;
   visibility: visible;
   transform: translate(-50%, -50%) scale(1);
   }

.code-tab.active  {
   color: rgb(167, 139, 250);
   background: rgba(167, 139, 250, 0.1);
   }

.code-tab.active::after  {
   content: "";
   position: absolute;
   bottom: 0px;
   left: 0px;
   right: 0px;
   height: 2px;
   background: rgb(167, 139, 250);
   }

.code-editor.active  {
   display: flex;
   flex-direction: column;
   }
JavaScript (fx-0463)
function toggleAccordion(header, type) {
      const item = header.parentElement;
      const accordion = item.parentElement;

      if (type === 'single') {
        // Close all other items in single mode
        accordion.querySelectorAll('.accordion-item').forEach(otherItem => {
          if (otherItem !== item) {
            otherItem.classList.remove('active');
          }
        });
      }

      item.classList.toggle('active');
    }

Customize

Options passed to the API or data-* attributes:

Option / propertyDefaultEffect
type in toggleAccordion(this, type) 'basic' Pass 'single' to allow only one section open at a time; 'basic' allows multiple open simultaneously.
.accordion-item.active .accordion-content { max-height } 200px Maximum expanded height. Increase if your content exceeds 200 px (code blocks, long forms).
.accordion-content { transition: max-height } 0.4s Open/close animation duration. 0.25s = snappy, 0.6s = slow and smooth.
.accordion-icon { transition: transform } 0.3s Chevron rotation duration — adjust in sync with the content transition.
.accordion-item { background } rgba(255,255,255,0.05) Background of each section. Replace with a brand color or transparent for a borderless accordion.
.accordion-single class on .accordion absent Enables the indigo border variant + glow on the active item. No extra JS required, HTML attribute only.
.active class on .accordion-item at load first item Pre-opens the marked item on initial render — remove it from all items to start fully collapsed.

FAQ

Why does the animation stop before all the content is visible?

The max-height is fixed at 200px in the CSS. If your content exceeds that, the section opens to 200 px and clips the rest. Increase max-height on .accordion-item.active .accordion-content to the actual height of your tallest content block.

Can multiple independent accordions coexist on the same page?

Yes. The toggleAccordion function walks up via parentElement to the direct parent accordion — each .accordion is isolated. Multiple instances work side by side without conflict, even with different modes ('basic' and 'single' mixed on the same page).

Does the effect respect prefers-reduced-motion?

No, not in the base version. CSS transitions run regardless of the system preference. To fix this, add: @media (prefers-reduced-motion: reduce) { .accordion-content, .accordion-icon { transition: none; } }