Skip to main content

Accordion

FancyAccordion is a single, reusable accordion built to work for every visual design (skin) an accordion needs across Fancy Etch templates — the same markup contract and script drive a plain FAQ list, a numbered full-width accordion, or an autoplaying showcase, with only a skin prop (plus CSS) differing between them.

Accordion — light and dark skin

Anatomy​

Two components: FancyAccordion (the container) and FancyAccordionItem (one question/answer pair, used inside its items slot — one instance per item).

The script binds to a small set of data-* attributes rather than classes, so any skin can restyle the component freely without touching behavior:

AttributeWherePurpose
data-fe-accRootMarks the accordion instance. Options (allow-multiple, open-first, autoplay, autoplay-interval) are read from plain attributes on this same element.
data-fe-acc-itemEach item wrapperOne question/answer pair.
data-fe-acc-buttonInside a headingThe disclosure trigger — must live inside <h2>–<h6> for the APG pattern.
data-fe-acc-panelSibling of the button's headingThe answer panel — animated with a pure-CSS grid-rows transition, no JS height measurement.

Props​

FancyAccordion​

PropTypeDefaultNotes
labelstring"Accordion"Accessible name for the whole accordion (aria-label).
openFirstbooleantrueOpens the first item on load.
allowMultiplebooleanfalseLets more than one item stay open at once.
syncIdstring""Optional exclusive-sync group id — see Sync groups. Usually you don't need it; wrapping the accordions is enough.
skinselect"underline"Visual design — underline, bordered, numbered, minimal. See Skins below.
indicatorselect"arrow"Trigger glyph shape — arrow, angle, dot. Independent of skin: any indicator can pair with any skin.
indicatorBgselect"filled"Whether the indicator sits in a colored/bordered badge (filled) or floats bare (bare).
showNumberbooleantrueShows the automatic item number. Only visible in the editor while skin is numbered — a plain on/off choice, not a responsive breakpoint, so it doesn't depend on viewport width.
autoplaybooleanfalseEnables automatic cycling — see Autoplay below.
(Autoplay options)conditionshown when autoplay is on
autoplayIntervalstring"6"Seconds between automatic advances. Only visible in the editor while autoplay is enabled. Toggling autoplay/autoplayInterval takes effect immediately in the builder — no page reload needed.
pauseHoverbooleantruePause the cycle while the pointer is over the accordion. Off = keeps running on hover; a manual click still pauses, and leaving resumes. See Autoplay.
disableOnMobilebooleanfalseDon't run autoplay below the tablet breakpoint (max-width: 767px). Re-evaluated live as the viewport crosses the breakpoint.
Progress bar (group)——Look of the bar (grouped in the panel).
progressBar.orientationselect"vertical"vertical (edge rail) or horizontal (bottom bar). The numbered skin is always horizontal. See Orientation.
progressBar.colorstring"var(--primary)"Bar fill color, per instance — a CSS color or variable.
progressBar.widthstring"3px"Bar thickness.

FancyAccordionItem​

PropTypeDefaultNotes
headingstring"I am a heading"The question text.
headingLevelselect"h3"h2–h6 — pick based on the surrounding page's heading outline.

The answer content itself goes in the item's content slot, not a prop — drop in any rich content (paragraphs, lists, images) as slot children.

Skins​

Four visual designs ship today, all built from the same two components — no wrapper element, no separate component per design. skin, indicator, and indicatorBg are independent choices; mix any indicator with any skin.

SkinDescription
underlineDefault — sliding underline beneath the trigger heading, icon in a rounded badge.
borderedBordered item cards, a fixed-width underline on the button itself. Pairs naturally with indicator="dot".
numberedFull-width layout — automatic 01, 02... numbering via a CSS counter, no per-item prop needed. Toggle the number column on/off with the showNumber prop (only shown in the editor for this skin).
minimalBare heading trigger, no icon — the cleanest look, and the one the autoplay progress rail was designed around, though you can use it with or without autoplay.

Each skin's full CSS lives together in one place in the Style Manager: select a FancyAccordion instance, open its element editor, and the .fe-acc--skins class shows a tab for every skin (separated by /*# Skin: Name #*/ comments inside it) — no need to hunt through the whole class list to find the one you want.

Sync groups​

Two or more accordions can act as one exclusive group: opening an item in any of them closes whatever's open in the others, so only one item is open across the whole group. The classic use is a FAQ split into columns.

There are two ways to form a group — pick whichever fits your layout:

  1. Wrap them (no id needed). Put the accordions inside one element carrying data-fe-acc-group. Everything inside that wrapper is one group. This is the simplest way and scopes naturally — a second wrapper elsewhere is its own independent group.
  2. Give them a syncId. Accordions sharing the same Sync group id form a group even if they're scattered around the page. Use this when they aren't siblings under one wrapper.

You can use either or both; an accordion with no wrapper and no syncId stays independent. Peers are found live, so accordions added later still join. Each accordion keeps its own keyboard behaviour — the group only coordinates which item is open.

<!-- No id: the wrapper is the group -->
<div data-fe-acc-group class="faq-columns">
<div class="fe-acc" data-fe-acc>…</div>
<div class="fe-acc" data-fe-acc>…</div>
</div>

Accessibility​

Follows the WAI-ARIA Accordion Pattern in full:

  • The trigger is a real <button> inside a heading (<h2>–<h6>), with aria-expanded and aria-controls kept in sync automatically.
  • The panel has role="region" and aria-labelledby pointing back at its button.
  • Closed panels are marked inert (not just visually hidden) — they're removed from both the tab order and the accessibility tree while animating shut, not only after the transition ends.
  • Keyboard: ↓ / ↑ move focus between triggers (wrapping at the ends), Home / End jump to the first/last trigger, Esc closes the currently open item and returns focus to its trigger.
  • All transitions respect prefers-reduced-motion.

CSS variables​

Every visual knob lives as a custom property on the root .fe-acc class — open it in the Style Manager and retheme an instance without touching a single nested selector. A skin (like the numbered full-width design) can override any of these instead of redeclaring rules.

VariableDefaultControls
--fe-acc-gap0Vertical space between items.
--fe-acc-border-colorvar(--base-light)Divider color between items.
--fe-acc-accentvar(--primary)The skin's accent color (e.g. a sliding underline).
--fe-acc-icon-size2.2remSize of the trigger's icon badge.
--fe-acc-icon-radius0.625remCorner radius of the icon badge.
--fe-acc-icon-colorvar(--primary)Icon color, closed state.
--fe-acc-icon-bgvar(--base-ultra-light)Icon badge background, closed state.
--fe-acc-icon-color-openvar(--white)Icon color, open state.
--fe-acc-icon-bg-openvar(--primary)Icon badge background, open state.
--fe-acc-icon-glyph-size0.8emSize of the indicator glyph itself, relative to its badge (kept smaller than the badge for a modern, minimal look).
--fe-acc-icon-glypharrow SVGThe glyph's shape, as a mask-image. This is how indicator swaps shapes with zero markup changes — the glyph isn't an inline <svg>, it's a mask on the icon element.
--fe-acc-heading-sizevar(--h3)Font size of the trigger text.
--fe-acc-content-gapvar(--content-gap)Row gap inside the answer panel.
--fe-acc-duration / --fe-acc-ease0.5s / easeOpen/close transition timing.
--fe-acc-progress-colorvar(--primary)Autoplay progress bar fill.
--fe-acc-progress-bgvar(--base-light)Autoplay progress bar track.
--fe-acc-progress-width4pxProgress bar thickness.
--fe-acc-progress-radius6pxProgress bar corner radius.
--fe-acc-progress-track2pxThe static rail running down the left edge while autoplay is on.

Autoplay & progress bar​

With autoplay on, the accordion cycles through its items automatically and shows a progress bar on the open item, indicating time left until the next advance. The bar is a plain CSS variable — --fe-acc-progress runs 0→1 and the fill is transform: scale(var(--fe-acc-progress)). The script advances it each frame (rAF), so there are no @keyframes (nothing to paste into a stylesheet) and pausing simply stops the loop, freezing the bar exactly where it is.

  • Runs only while visible. An IntersectionObserver starts/stops the cycle as the accordion enters/leaves the viewport.
  • Pauses on interaction, then resumes — it no longer turns off for good on a click. Keyboard focus and opening an item by hand always pause (the bar freezes); hover pauses too unless you turn pauseHover off, in which case it keeps running on hover and only a manual click pauses. Either way, leaving resumes from the item you left open — the remaining time is tracked so the next advance still lands on schedule.
  • disableOnMobile skips autoplay below the tablet breakpoint (max-width: 767px), re-checked live as the viewport crosses it.
  • Theme the bar per instance with progressBar.color and progressBar.width — no Style Manager edit needed.
  • Respects prefers-reduced-motion — autoplay never starts at all for visitors who've asked for reduced motion.

Orientation​

progressOrientation (in Autoplay options) sets which way the bar runs:

ValueLook
vertical (default)A rail on the item's inline-start edge (a full-height rail on underline/minimal, a bar flush inside the card on bordered).
horizontalA bar along each item's block-end edge, filling left→right — clean in every skin.

The numbered skin always runs the bar horizontally regardless of this option: a left rail would collide with the number column.

No stylesheet to set up

Earlier versions needed a hand-pasted "Fancy Accordion" @keyframes stylesheet. That's gone — the variable-driven bar needs no Style Manager setup, so autoplay works the moment you switch it on.

Mobile​

Accordion on mobile, light and dark