DOM & Browsereasy

Build an expandable panel (single accordion item)

Build a component with a header and collapsible body. Clicking the header toggles visibility. The header must be keyboard accessible (Enter/Space) and expose `aria-expanded` on the control that opens/closes the panel.

Asked at Meta, Google, TikTok

#react#accessibility#ARIA#useState

Answer

function ExpandablePanel({ title, children }) {
  const [open, setOpen] = React.useState(false)
  const id = React.useId()
  const headerId = `${id}-header`
  const panelId = `${id}-panel`

  const onKeyDown = (e) => {
    if (e.key === 'Enter' || e.key === ' ') {
      e.preventDefault()
      setOpen((o) => !o)
    }
  }

  return (
    <div>
      <button
        id={headerId}
        type="button"
        aria-expanded={open}
        aria-controls={panelId}
        onClick={() => setOpen((o) => !o)}
        onKeyDown={onKeyDown}
      >
        {title}
      </button>
      <div id={panelId} role="region" aria-labelledby={headerId} hidden={!open}>
        {open ? children : null}
      </div>
    </div>
  )
}

// Alternative: keep content in DOM but hide with CSS for SEO/animations;
// then use aria-hidden and inert on the collapsed body instead of hidden.

// Interview notes:
// - aria-expanded belongs on the element that controls the panel.
// - Linking aria-controls helps assistive tech; ids must be unique (useId).
// - For a real accordion group, only one section open at a time lives in parent state.

Source: common React screen interview

Practise more DOM & Browser questions →