Skip to the solution
EasyMachine Coding12 min read

Build an Accordion component

163 views

The problem

Question presented to candidate: "Our help page has a long FAQ. Build an accordion component: a list of questions where clicking a question shows or hides its answer. By default only one answer should be open at a time, but the same component should also support letting several stay open. Make it usable with a keyboard and a screen reader."

Requirements:

  • Data-driven: the component takes an array of items (id, title, content) and renders one header and one panel per item.
  • Clicking a header toggles its panel. A prop switches between single-open (opening one closes the others) and multi-open mode; a defaultOpen list sets the initial state.
  • Each header is a real <button> inside a heading, with aria-expanded and aria-controls; each panel is a region labelled by its header. Closed panels must not be reachable with Tab.
  • Keyboard: Enter and Space toggle (native button behaviour); Arrow Down / Arrow Up move between headers and wrap; Home and End jump to the first and last header.
  • Opening and closing animates the height smoothly, and the animation is turned off for users who ask for reduced motion.

What a strong answer should cover:

  • A single source of truth for which panels are open (a list of ids), with the single-open view derived from it rather than kept in a second piece of state.
  • Correct WAI-ARIA accordion wiring: heading plus button, aria-expanded, aria-controls, role="region" with aria-labelledby, and unique ids per instance.
  • Why closed content must be removed from the tab order and the accessibility tree (hidden or inert), not just squashed to zero height.
  • Animating height without measuring it (the grid-template-rows: 0fr to 1fr technique) and respecting prefers-reduced-motion.
  • Roving focus between headers with arrow keys, and leaving Enter and Space to the native button.

Clarifying questions expected:

  • "Should one panel always stay open, or may every panel be closed?"
  • "Do panels hold heavy content that should only render when first opened, or is it fine to render everything up front?"
  • "Does the open state need to survive a reload or be shareable in the URL?"

Code / implementation expected: Yes. A working component in the chosen framework, with a small demo that toggles between single and multi mode.

  • React
  • UI
  • Accessibility

Try it yourself

Sketch your approach before you read the solution. That is what the interview tests.

Stuck? Get a hint.

A short nudge toward the approach. It will not give the answer away.

Solution

The solution is hidden so you can try first

12 min read ยท 9 sections

React solution

Every file of the working solution. Open it in the playground to run and change it.

ReactComplete solution
import { useState } from "react";
import Accordion from "./src/components/Accordion";

const FAQ = [
  {
    id: "shipping",
    title: "How long does shipping take?",
    content:
      "Orders leave our warehouse within 24 hours and arrive in 2 to 4 working days.",
  },
  {
    id: "returns",
    title: "Can I return an item?",
    content:
      "Yes. Send it back unused within 30 days and we refund the full price.",
  },
  {
    id: "warranty",
    title: "Is there a warranty?",
    content:
      "Every product has a two year warranty that covers manufacturing faults.",
  },
  {
    id: "support",
    title: "How do I contact support?",
    content:
      "Use the chat button or email help@example.com; we reply within one day.",
  },
];

export default function App() {
  const [allowMultiple, setAllowMultiple] = useState(false);
  return (
    <main className="page">
      <h1>Frequently asked questions</h1>
      <label className="mode">
        <input
          type="checkbox"
          checked={allowMultiple}
          onChange={(e) => setAllowMultiple(e.target.checked)}
        />
        Allow several panels open at once
      </label>
      <Accordion
        items={FAQ}
        allowMultiple={allowMultiple}
        defaultOpen={["shipping"]}
      />
    </main>
  );
}

Discussion

Other approaches, follow-ups and how it went in real interviews.

Sign in to join the discussion.

No comments yet. Share how you would answer it.

Question 24 of 107 in Machine coding

Keep your momentum going.

Mark this question solved to track your progress, then take the next one while it is fresh.

Up nextEasy

Build a Countdown Timer

Continue