Live: try it with the mouse and the keyboard (Tab, arrows, Escape).

Accordion UI component for websites and web apps, shown in Steadyfit, a fictional health product. Shows an accordion with one section open, a disabled section, chevrons that rotate, and every header state (default, hover, focus-visible, open, disabled). Minimal style: cool neutrals, Inter, 8px corners and soft shadows. Comes with copyable HTML, CSS and a few lines of plain JavaScript (keyboard support and ARIA per the WAI-ARIA Authoring Practices), a live demo, and a DESIGN.md with light and dark colour tokens.
#f3f8fd · surface #ffffff · text #141c26 · muted #596472 · primary #005eb8 · accent #6e6ab3#070d13 · surface #171e27 · text #ebeff4 · muted #a8b2bf · primary #60a7ff · accent #bfc0ffPaste the HTML where the component goes, the CSS into your stylesheet and the script before </body>. The tokens block holds the light and dark colours; swap in your own.
<div class="mgd-acc">
<div class="mgd-acc__item">
<h3 class="mgd-acc__h"><button class="mgd-acc__btn" type="button" id="acc-included-btn" aria-expanded="true" aria-controls="acc-included">What's included in the plan?<span class="mgd-acc__icon"><svg class="i" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M5 9l7 7 7-7"/></svg></span></button></h3>
<div class="mgd-acc__panel" id="acc-included" role="region" aria-labelledby="acc-included-btn"><p>Unlimited workouts, habit tracking, weekly check-ins with your coach and offline access on two devices.</p></div>
</div>
<div class="mgd-acc__item">
<h3 class="mgd-acc__h"><button class="mgd-acc__btn" type="button" id="acc-billing-btn" aria-expanded="false" aria-controls="acc-billing">How does billing work?<span class="mgd-acc__icon"><svg class="i" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M5 9l7 7 7-7"/></svg></span></button></h3>
<div class="mgd-acc__panel" id="acc-billing" role="region" aria-labelledby="acc-billing-btn" hidden><p>You pay monthly or yearly. Yearly plans are billed once and renew on the same date; we email you a week before.</p></div>
</div>
<div class="mgd-acc__item">
<h3 class="mgd-acc__h"><button class="mgd-acc__btn" type="button" id="acc-pause-btn" aria-expanded="false" aria-controls="acc-pause">Can I pause my plan?<span class="mgd-acc__icon"><svg class="i" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M5 9l7 7 7-7"/></svg></span></button></h3>
<div class="mgd-acc__panel" id="acc-pause" role="region" aria-labelledby="acc-pause-btn" hidden><p>Yes, for up to 8 weeks a year. Your streaks and history stay as they are while you are paused.</p></div>
</div>
<div class="mgd-acc__item">
<h3 class="mgd-acc__h"><button class="mgd-acc__btn" type="button" id="acc-family-btn" aria-expanded="false" aria-controls="acc-family" aria-disabled="true">Family sharing (coming soon)<span class="mgd-acc__icon"><svg class="i" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M5 9l7 7 7-7"/></svg></span></button></h3>
<div class="mgd-acc__panel" id="acc-family" role="region" aria-labelledby="acc-family-btn" hidden><p>Family plans arrive in the spring.</p></div>
</div>
</div>/* Tokens (light + dark) */
:root{--bg:#f3f8fd;--surface:#ffffff;--border:#cdd7e4;--text:#141c26;--muted:#596472;--primary:#005eb8;--on-primary:#ffffff;--accent:#6e6ab3;--font-h:"Inter",Georgia,serif;--font-b:"Inter",system-ui,sans-serif;--hw:600;
--c-bw:1px;--c-line:var(--border);--c-r:8px;--c-pill:8px;--c-sh:0 1px 2px rgb(0 0 0 / .06);--c-pop:0 12px 32px rgb(0 0 0 / .14);--c-tt:none;--c-ls:0;--c-fw:500;--c-fs:14px;--c-ring:2px solid var(--primary);--c-ind:2px;color-scheme:light}
@media (prefers-color-scheme:dark){:root:not([data-theme="light"]){--bg:#070d13;--surface:#171e27;--border:#2c343e;--text:#ebeff4;--muted:#a8b2bf;--primary:#60a7ff;--on-primary:#111111;--accent:#bfc0ff;color-scheme:dark}
}
:root[data-theme="dark"]{--bg:#070d13;--surface:#171e27;--border:#2c343e;--text:#ebeff4;--muted:#a8b2bf;--primary:#60a7ff;--on-primary:#111111;--accent:#bfc0ff;color-scheme:dark}
/* Component */
.mgd-sr{position:absolute!important;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0 0 0 0);white-space:nowrap;border:0}
.mgd-acc{max-width:720px;border-top:var(--c-bw) solid var(--border)}
.mgd-acc__item{border-bottom:var(--c-bw) solid var(--border)}
.mgd-acc__h{margin:0;font:inherit}
.mgd-acc__btn{width:100%;display:flex;align-items:center;justify-content:space-between;gap:16px;min-height:56px;padding:14px 4px;border:0;background:none;color:var(--text);font:600 16px/1.35 var(--font-b);text-transform:var(--c-tt);letter-spacing:var(--c-ls);text-align:left;cursor:pointer;border-radius:var(--c-r);transition:background-color .12s}
.mgd-acc__btn:hover,.mgd-acc__btn.is-hover{background:color-mix(in oklab,var(--primary) 7%,transparent)}
.mgd-acc__btn:focus-visible,.mgd-acc__btn.is-focus{outline:var(--c-ring);outline-offset:-2px}
.mgd-acc__btn[aria-disabled="true"],.mgd-acc__btn.is-off{opacity:.45;cursor:not-allowed;background:none}
.mgd-acc__icon{flex:none;width:28px;height:28px;display:grid;place-items:center;border-radius:var(--c-r);background:color-mix(in oklab,var(--primary) 12%,transparent);color:var(--text);transition:transform .16s}
.mgd-acc__btn[aria-expanded="true"] .mgd-acc__icon,.mgd-acc__btn.is-on .mgd-acc__icon{transform:rotate(180deg)}
.mgd-acc__panel{padding:0 4px 18px;color:var(--muted);max-width:62ch}
.mgd-acc__panel p{margin:0}
@media (prefers-reduced-motion:reduce){.mgd-acc,.mgd-acc *{transition:none!important;animation-duration:2.4s!important}}document.querySelectorAll(".mgd-acc").forEach(function (acc) {
var btns = [].slice.call(acc.querySelectorAll(".mgd-acc__btn"));
acc.addEventListener("click", function (e) {
var b = e.target.closest(".mgd-acc__btn"); if (!b || b.getAttribute("aria-disabled") === "true") return;
var open = b.getAttribute("aria-expanded") !== "true";
b.setAttribute("aria-expanded", open); document.getElementById(b.getAttribute("aria-controls")).hidden = !open;
});
acc.addEventListener("keydown", function (e) {
var i = btns.indexOf(document.activeElement); if (i < 0) return;
var n = e.key === "ArrowDown" ? btns[(i + 1) % btns.length] : e.key === "ArrowUp" ? btns[(i - 1 + btns.length) % btns.length] : e.key === "Home" ? btns[0] : e.key === "End" ? btns[btns.length - 1] : null;
if (n) { e.preventDefault(); n.focus(); }
});
});## Component: Accordion
Stacked sections that expand in place; each header is a real button inside a heading.
- **Pattern:** WAI-ARIA Authoring Practices, Accordion (https://www.w3.org/WAI/ARIA/apg/patterns/accordion/)
- **Roles and attributes:** Each header is a <button> inside an <h3> with aria-expanded and aria-controls; each panel has role="region" and aria-labelledby, and is hidden with the hidden attribute when closed.
- **States drawn:** default, hover, focus-visible, open, disabled
- **Focus:** a visible `:focus-visible` outline (2px solid primary), never removed
- **Style knobs (minimal):** border 1px, corners 8px, shadow `0 1px 2px rgb(0 0 0 / .06)`, labels sentence case
- **Motion:** transitions are short (≤160ms) and switched off under `prefers-reduced-motion: reduce`
- **Code:** HTML + CSS + a few lines of plain JavaScript (no libraries); colours come only from the tokens above, so light and dark both work
### Keyboard
- **Enter / Space:** expand or collapse the focused section
- **Up / Down arrow:** previous / next header
- **Home / End:** first / last header
### Licence
Original Made Good Designs code: free to use and adapt in any project, including commercial ones, with no credit needed. Fonts are Google Fonts under their own licences.Add the Made Good Designs library to your assistant once. Then ask for UI references, brand palettes, font pairings and design tokens in any chat.
https://madegooddesigns.com/inspiration/mcp?ref=ui-accordion-uiSettings → Connectors → Add custom connector → paste the URL.
Settings → Apps & Connectors → Advanced → Developer mode → Create → paste the URL.
One click, then confirm in Cursor.
One click, then confirm in VS Code (Copilot agent mode).
claude mcp add --transport http made-good-designs https://madegooddesigns.com/inspiration/mcp?ref=ui-accordion-ui
gemini mcp add --transport http made-good-designs https://madegooddesigns.com/inspiration/mcp?ref=ui-accordion-ui
Add this to the app's MCP config (Windsurf: mcp_config.json).
Fonts: Inter (Google Fonts)
Prompt copied: paste it into the chat that just opened.
Writing about this component?
search_ui_screens (e.g. “billing settings, editorial style”), get_ui_flow for a whole journey, and get_ui_screen_code to pull the HTML and DESIGN.md straight into your project.