AniUI Academy

Build an accordion

easyUI Components+160 XP

Render three FAQ-style panels, each with a clickable header and hidden body content.

Clicking a header's panel open toggles it — but opening one panel must close whichever other panel was open, since only one can be expanded at a time.

Examples

// Initial render — nothing expanded.
<Accordion />
// → three headers, no body visible.

// Click panel 1's header
// → body-1 appears.

// Click panel 2's header
// → body-1 disappears, body-2 appears.

Opening another panel implicitly closes the one that was open.

// Panel body is absent from the DOM while closed,
// not just hidden with CSS:
{openId === panel.id ? (
  <div data-testid={`accordion-body-${panel.id}`}>
    {panel.body}
  </div>
) : null}

The grader counts `[data-testid^="accordion-body-"]` nodes, so hiding with `display: none` fails.

What it has to do

  • Each panel header is a `<button data-testid="accordion-header-ID">`.
  • Each panel body renders only while open, as `<div data-testid="accordion-body-ID">` — absent from the DOM while closed, not just hidden.
  • All panels start closed.
  • Opening a panel closes any other panel that was open — at most one body is ever present at once.
  • Clicking the header of the currently-open panel closes it, leaving none open.

Notes

  • Model open state as a single `openId` rather than an array of booleans — the "only one open" invariant falls out, and toggling becomes `openId === id ? null : id`.
  • A production-grade accordion should also expose `aria-expanded` on each header and link the header to its body with `aria-controls` / `id`, so screen readers announce the state change.
  • Clicking the open panel's own header closes it (returns to zero-open) — don't skip the toggle-off path.
Asked atGoogleMicrosoftAtlassian

Stuck? The react course covers the ideas this problem is built on.

import { useState } from "react";

const PANELS = [
  { id: 1, title: "What is this?", body: "A frequently-asked-questions accordion." },
  { id: 2, title: "How do I use it?", body: "Click a question to reveal its answer." },
  { id: 3, title: "Can more than one be open?", body: "No — opening one should close any other." },
];

export default function App() {
  const [openId, setOpenId] = useState(null);

  // TODO: clicking a header should toggle its panel, and opening one
  // panel should close whichever other one was open.

  return (
    <div style={{ fontFamily: "sans-serif", padding: 16 }}>
      {PANELS.map((panel) => (
        <div key={panel.id} style={{ borderBottom: "1px solid #ddd" }}>
          <button
            data-testid={`accordion-header-${panel.id}`}
            style={{ width: "100%", textAlign: "left", padding: 12, fontWeight: "bold" }}
          >
            {panel.title}
          </button>
          <div data-testid={`accordion-body-${panel.id}`} style={{ padding: 12 }}>
            {panel.body}
          </div>
        </div>
      ))}
    </div>
  );
}

5 tests · +160 XP

Discussion

Sign in to post
Sign in to join the conversation.Sign in

No comments yet. Be the first to say something.