Free pack

Accordion — <mv-accordion>

CSS accordion on native <details>: animated height (::details-content + interpolate-size), chevron or plus/minus, bordered, separated and card variants; optional <mv-accordion type="single">. Also covers Collapsible.

CategoryData display
TypeWeb Component (<mv-accordion>)
Statusstable
Keywordsaccordion, accordéon, collapsible, details, faq, disclosure, expand

When to use

Avoid when

Install

node scripts/add.mjs accordion --out ./src/marvelous

AI agent with the Marvelous UI MCP server: install_components({ slugs: ["accordion"], target_dir: "<absolute path>/src/marvelous", framework: "react" }).

Files copied (dependencies included): tokens/tokens.css, core/base.css, core/dom.js, core/element.js, components/accordion/accordion.css, components/accordion/accordion.js.

Usage

Canonical markup — start from it and customize with attributes, data-* and CSS variables:

<div style="display:grid;grid-template-columns:repeat(auto-fit,minmax(min(100%,20rem),1fr));gap:2.5rem;width:100%;align-items:start">

  <!-- Default + single (native name group) -->
  <mv-accordion type="single">
    <div class="mv-accordion">
      <details class="mv-accordion-item" data-value="shipping" open>
        <summary>How long does shipping take?</summary>
        <div class="mv-accordion-content">
          <p>Orders placed before 2 p.m. ship the same day. Allow 1–2 business days within the continental US and 3–5 business days for Canada and Mexico.</p>
        </div>
      </details>
      <details class="mv-accordion-item" data-value="returns">
        <summary>Can I return an item?</summary>
        <div class="mv-accordion-content">
          <p>Yes, you have 30 days from delivery. The return label is available in your account, and refunds are issued within 5 days.</p>
        </div>
      </details>
      <details class="mv-accordion-item" data-value="payment">
        <summary>Which payment methods do you accept?</summary>
        <div class="mv-accordion-content">
          <p>Credit cards (Visa, Mastercard, American Express), Apple Pay, PayPal and ACH transfer for business accounts.</p>
        </div>
      </details>
      <details class="mv-accordion-item" data-value="invoice">
        <summary>How do I get an invoice?</summary>
        <div class="mv-accordion-content">
          <p>Every invoice is emailed when your order ships and can be downloaded as a PDF from the “Orders” tab.</p>
        </div>
      </details>
    </div>
  </mv-accordion>

  <!-- Bordered, icons + subtitles, plus/minus -->
  <div class="mv-accordion" data-variant="bordered" data-icon="plus">
    <details class="mv-accordion-item" open>
      <summary>
        <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M20 13c0 5-3.5 7.5-7.66 8.95a1 1 0 0 1-.67-.01C7.5 20.5 4 18 4 13V6a1 1 0 0 1 1-1c2 0 4.5-1.2 6.24-2.72a1.17 1.17 0 0 1 1.52 0C14.51 3.81 17 5 19 5a1 1 0 0 1 1 1z"/></svg>
        <span class="mv-accordion-heading">Account security<span class="mv-accordion-subtitle">Password, two-factor authentication</span></span>
      </summary>
      <div class="mv-accordion-content">
        <p>Turn on two-factor authentication to protect your account: you’ll be asked for a one-time code every time you sign in on a new device.</p>
      </div>
    </details>
    <details class="mv-accordion-item">
      <summary>
        <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M6 8a6 6 0 0 1 12 0c0 7 3 9 3 9H3s3-2 3-9"/><path d="M10.3 21a1.94 1.94 0 0 0 3.4 0"/></svg>
        <span class="mv-accordion-heading">Notifications<span class="mv-accordion-subtitle">Email, mobile, weekly digest</span></span>
      </summary>
      <div class="mv-accordion-content">
        <p>Choose the events you care about: new mentions, comments on your documents or due-date reminders.</p>
      </div>
    </details>
    <details class="mv-accordion-item">
      <summary>
        <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><rect x="2" y="5" width="20" height="14" rx="2"/><path d="M2 10h20"/></svg>
        <span class="mv-accordion-heading">Billing<span class="mv-accordion-subtitle">Team plan · $228/year</span></span>
      </summary>
      <div class="mv-accordion-content">
        <p>Next charge on Nov 1, 2026 to the card ending in 4242. Invoices remain available for 10 years.</p>
      </div>
    </details>
  </div>

  <!-- Separated -->
  <div class="mv-accordion" data-variant="separated">
    <details class="mv-accordion-item">
      <summary>Can I switch plans mid-year?</summary>
      <div class="mv-accordion-content"><p>Yes, the difference is prorated and appears on your next invoice.</p></div>
    </details>
    <details class="mv-accordion-item" open>
      <summary>Where is my data hosted?</summary>
      <div class="mv-accordion-content"><p>All data is hosted in Virginia and Frankfurt, encrypted at rest and in transit.</p></div>
    </details>
    <details class="mv-accordion-item">
      <summary>Do you offer a nonprofit discount?</summary>
      <div class="mv-accordion-content"><p>Registered nonprofits get 50% off with proof of their nonprofit status.</p></div>
    </details>
  </div>

  <!-- Card + collapsible -->
  <div style="display:grid;gap:1.5rem">
    <mv-accordion type="single">
      <div class="mv-accordion" data-variant="card" data-icon="start">
        <details class="mv-accordion-item" open>
          <summary>Step 1 · Import your contacts</summary>
          <div class="mv-accordion-content"><p>Drop in a CSV file or connect Google Contacts. Duplicates are merged automatically.</p></div>
        </details>
        <details class="mv-accordion-item">
          <summary>Step 2 · Create a segment</summary>
          <div class="mv-accordion-content"><p>Filter by city, sign-up date or last purchase to target your campaigns.</p></div>
        </details>
      </div>
    </mv-accordion>

    <details class="mv-collapsible" style="font-size:.875rem">
      <summary style="display:flex;align-items:center;gap:.5rem;font-weight:500">
        @camille has 3 starred repositories
        <svg class="mv-accordion-chevron" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="m6 9 6 6 6-6"/></svg>
      </summary>
      <div class="mv-accordion-content" style="display:grid;gap:.5rem;padding-top:.75rem">
        <code style="padding:.5rem .75rem;border:1px solid var(--mv-border);border-radius:var(--mv-radius-md);font-family:var(--mv-font-mono);font-size:.8125rem;color:var(--mv-fg)">marvelous/ui</code>
        <code style="padding:.5rem .75rem;border:1px solid var(--mv-border);border-radius:var(--mv-radius-md);font-family:var(--mv-font-mono);font-size:.8125rem;color:var(--mv-fg)">marvelous/tokens</code>
        <code style="padding:.5rem .75rem;border:1px solid var(--mv-border);border-radius:var(--mv-radius-md);font-family:var(--mv-font-mono);font-size:.8125rem;color:var(--mv-fg)">marvelous/icons</code>
      </div>
    </details>
  </div>
</div>

API

Attributes

NameTypeDefaultDescription
typesingle | multiplemultipleOn <mv-accordion>: single allows only one open item (native name attribute set automatically, JS fallback).
data-variantbordered | separated | card(simple dividers)On .mv-accordion: a single outlined box, separate boxes, or filled tiles where the open item lifts.
data-iconchevron | plus | start | nonechevronOn .mv-accordion or an item: chevron on the right, plus that turns into minus, chevron before the label, or no indicator.
namestringNative on <details>: same name = exclusive group, no JS.
openbooleanNative on <details>: open on load.
data-valuestringOn an item: value reported in mv-change (its index otherwise).

Properties

NameTypeDescription
valuestring[]Values of the open items; assign it to open/close items programmatically.

Events

NameDescription
mv-changeAn item opened or closed. detail: { value: string[], item, open }.

Content structure

NameDescription
details.mv-accordion-item > summaryTrigger; optional leading <svg> icon, .mv-accordion-heading + .mv-accordion-subtitle for a two-line header.
.mv-accordion-contentPanel content (fade + blur on open).

CSS classes

NameDescription
mv-accordionItems container.
mv-accordion-itemOn <details>: one accordion item.
mv-accordion-contentContent panel.
mv-accordion-heading / -subtitleTitle and subtitle inside the <summary>.
mv-collapsibleCollapsible: a standalone <details class="mv-collapsible">, same height animation, free-form <summary> (style it yourself, e.g. mv-button).
mv-accordion-chevronOn an <svg> inside a <summary>: rotates 180° on open.

Accessibility

Built on native <details>/<summary>: button role, expanded state announced, Enter/Space. <mv-accordion> adds Up/Down/Home/End between triggers. Closed content is out of the accessibility tree and still findable with Ctrl+F (opens automatically). Reduced motion: instant open. Browsers without ::details-content: instant open.