Accordion

아코디언

A vertical list of headers that expand to reveal body content, usually limited to one open panel at a time.

Also known as: CollapseDisclosureExpanderExpansion panel
···
html
<div class="acc">
  <div class="item"><button class="head" aria-expanded="true" aria-controls="p1" id="h1">가격 정책</button>
    <div class="panel" id="p1" data-open role="region" aria-labelledby="h1"><div class="inner">월 9,900원부터 시작하고 언제든 해지할 수 있어요.</div></div></div>
  <div class="item"><button class="head" aria-expanded="false" aria-controls="p2" id="h2">환불 규정</button>
    <div class="panel" id="p2" role="region" aria-labelledby="h2"><div class="inner">구매 후 7일 이내라면 100% 환불됩니다.</div></div></div>
  <div class="item"><button class="head" aria-expanded="false" aria-controls="p3" id="h3">지원 채널</button>
    <div class="panel" id="p3" role="region" aria-labelledby="h3"><div class="inner">이메일과 채팅으로 상시 지원합니다.</div></div></div>
</div>
css
.acc{width:min(380px,92%);display:grid;gap:8px}
.item{border:1px solid var(--line);border-radius:10px;overflow:hidden;background:var(--surface)}
.head{width:100%;text-align:left;padding:10px 14px;border:0;background:none;color:var(--fg);font-size:13px;font-weight:600;cursor:pointer;display:flex;justify-content:space-between;align-items:center}
.head::after{content:"+";color:var(--accent);font-size:16px;transition:transform .25s}
.head[aria-expanded=true]::after{transform:rotate(45deg)}
.panel{display:grid;grid-template-rows:0fr;transition:grid-template-rows .28s ease}
.panel[data-open]{grid-template-rows:1fr}
.inner{overflow:hidden;min-height:0;padding:0 14px;color:var(--muted);font-size:12px;line-height:1.5}
.panel[data-open] .inner{padding-bottom:12px}
js
const heads = [...document.querySelectorAll('.head')];
const panels = [...document.querySelectorAll('.panel')];
function show(i) {
  heads.forEach((h, idx) => h.setAttribute('aria-expanded', String(idx === i)));
  panels.forEach((p, idx) => idx === i ? p.setAttribute('data-open', '') : p.removeAttribute('data-open'));
}
let auto = true, idx = 0;
heads.forEach((h, i) => h.addEventListener('click', () => {
  auto = false;
  const willOpen = h.getAttribute('aria-expanded') !== 'true';
  show(willOpen ? i : -1);
}));
setInterval(() => { if (!auto) return; idx = (idx + 1) % heads.length; show(idx); }, 2400);

Each header button pairs with a panel below it. The header's aria-expanded reflects open state and aria-controls points at the panel's id. Animating the height with a CSS grid-template-rows 0fr↔1fr trick is lighter than measuring pixel height in JS.

It differs from a tree view in nesting depth — an accordion usually toggles single-level sections, while a tree view nests arbitrarily deep like folders inside folders. It differs from tabs in layout — tabs sit in a row and swap a single content area, while accordion panels stack vertically and several can be open at once.

Headers must be real buttons (not a div with onclick) so Tab order and Enter/Space toggling work for free. Give each panel role="region" and aria-labelledby pointing at its header so screen-reader users can skim it like a table of contents.

When to use

Use it to organize sections where vertical space is tight — FAQs, filter groups, mobile screens. 3–7 items per group is a reasonable range.