UI DeployDesign languages Themes For agents llms.txt

Warm Editorial — disclosure

FAQ Accordion

Each item is its own rounded card with a 12px gap, rather than rows sharing hairline dividers. Built on real buttons with aria-expanded and aria-controls, and animated with grid-template-rows so the panel height is never hard-coded.

Open preview
Theme
Warm Editorial
Category
disclosure
JavaScript
16 lines, no dependencies
Breakpoint
none
Min width
320px

Paste this into Claude, Cursor or Copilot — or point the agent at https://ui-deploy.com/r/warm-editorial/accordion/prompt.md

# FAQ Accordion — Warm Editorial

Paste this whole file into Claude, Cursor or Copilot.

---

## What to build

A disclosure list where **each item is its own rounded card** with a 12px gap
between items — not a stack of rows sharing hairline dividers. 24px corners.

Each row: question on the left, a circled `+` on the right that rotates 45° into
an `×` when the item opens.

---

## Tokens

```css
:root{
  --bg2:#F6F3ED; --bg3:#E4DED2; --border:#DAD3C6;
  --text:#22201D; --text2:#5C574F;
  --accent:#A38A6A; --accent-text:#7D6644;
  --accent-s:rgba(163,138,106,.12); --accent-b:rgba(163,138,106,.30);
  --radius-lg:24px;
  --font-display:'Inter Tight',system-ui,sans-serif;
  --font-body:'Inter',system-ui,sans-serif;
  --ease:cubic-bezier(.22,.61,.36,1);
}
[data-theme="dark"]{
  --bg2:#1E1A17; --bg3:#262119; --border:#2E2822;
  --text:#EDE7DD; --text2:#A79E92;
  --accent:#B39B7C; --accent-text:#C0A888;
  --accent-s:rgba(179,155,124,.13); --accent-b:rgba(179,155,124,.28);
}
```

---

## Rules — these are not preferences

1. **Use a real `<button>` with `aria-expanded` and `aria-controls`.** A `<div>`
   with a click handler is not a disclosure control. Wrap it in a heading
   (`<h3>`) so the questions appear in the document outline.
2. **Reset the button's default padding.** A `<button>` spanning a card row keeps
   its UA padding otherwise, and it shows up as an unexplained inset that is
   maddening to debug.
3. **Animate with `grid-template-rows: 0fr → 1fr`**, with `overflow:hidden` on the
   inner wrapper. Do not measure `scrollHeight` in JS and do not animate
   `max-height` to a guessed value.
4. **Put `hidden` back on after the collapse finishes**, not at click time — remove
   it before opening. Toggling it immediately makes the panel snap instead of
   animating, and leaving it off keeps collapsed content in the tab order.
5. **The `+` rotates 45°.** No chevron, no caret, no icon swap.
6. **Cards separate, never dividers.** A shared-divider list is a different
   language; this one breathes.
7. Icons are inline SVG, `stroke="currentColor"`, `fill="none"`. No emoji.
8. `:focus-visible` sets `outline` only — never `border-radius`.

---

## Variants

- **One open at a time** — before opening, close any sibling with
  `aria-expanded="true"`. Multiple-open is the default here because FAQ answers
  are usually compared, not read in sequence.
- **Answer with a link or list** — put it inside `.we-acc-inner`; the padding
  already accounts for it.

---

## Reference implementation

See `code.html` — 16 lines of dependency-free JS.

FAQ Accordion — Warm Editorial

Paste this whole file into Claude, Cursor or Copilot.


What to build

A disclosure list where each item is its own rounded card with a 12px gap between items — not a stack of rows sharing hairline dividers. 24px corners.

Each row: question on the left, a circled + on the right that rotates 45° into an × when the item opens.


Tokens

:root{
  --bg2:#F6F3ED; --bg3:#E4DED2; --border:#DAD3C6;
  --text:#22201D; --text2:#5C574F;
  --accent:#A38A6A; --accent-text:#7D6644;
  --accent-s:rgba(163,138,106,.12); --accent-b:rgba(163,138,106,.30);
  --radius-lg:24px;
  --font-display:'Inter Tight',system-ui,sans-serif;
  --font-body:'Inter',system-ui,sans-serif;
  --ease:cubic-bezier(.22,.61,.36,1);
}
[data-theme="dark"]{
  --bg2:#1E1A17; --bg3:#262119; --border:#2E2822;
  --text:#EDE7DD; --text2:#A79E92;
  --accent:#B39B7C; --accent-text:#C0A888;
  --accent-s:rgba(179,155,124,.13); --accent-b:rgba(179,155,124,.28);
}

Rules — these are not preferences

  1. Use a real <button> with aria-expanded and aria-controls. A <div> with a click handler is not a disclosure control. Wrap it in a heading (<h3>) so the questions appear in the document outline.
  2. Reset the button's default padding. A <button> spanning a card row keeps its UA padding otherwise, and it shows up as an unexplained inset that is maddening to debug.
  3. Animate with grid-template-rows: 0fr → 1fr, with overflow:hidden on the inner wrapper. Do not measure scrollHeight in JS and do not animate max-height to a guessed value.
  4. Put hidden back on after the collapse finishes, not at click time — remove it before opening. Toggling it immediately makes the panel snap instead of animating, and leaving it off keeps collapsed content in the tab order.
  5. The + rotates 45°. No chevron, no caret, no icon swap.
  6. Cards separate, never dividers. A shared-divider list is a different language; this one breathes.
  7. Icons are inline SVG, stroke="currentColor", fill="none". No emoji.
  8. :focus-visible sets outline only — never border-radius.

Variants

  • One open at a time — before opening, close any sibling with

aria-expanded="true". Multiple-open is the default here because FAQ answers are usually compared, not read in sequence.

  • Answer with a link or list — put it inside .we-acc-inner; the padding

already accounts for it.


Reference implementation

See code.html — 16 lines of dependency-free JS.