Katkat

Build Accessible Data-Loading Popovers for Multiple Buttons

AmazonFrontend Engineer · Onsite

Last updated

This problem tests the ability to build a robust, accessible UI component that manages asynchronous data fetching, state synchronization, and DOM-level focus management.

The Task

Create a reusable Popover component in React that triggers a data fetch upon opening and displays the result. Multiple buttons on the page may trigger different popovers, but only one should be open at a time.

Requirements

  1. Accessibility: Use appropriate ARIA roles (aria-expanded, aria-describedby, aria-busy) and ensure keyboard focus is trapped or correctly managed when the popover opens.
  2. State Management: Show a loading state while fetching, and handle the content display upon success.
  3. Race Condition Protection: If a user clicks a button, clicks another quickly, then clicks the first again, ensure the popover shows the result of the latest request triggered for that specific instance.
  4. Adaptive Positioning: The popover must appear anchored to the triggering button. You can assume a basic absolute positioning logic or describe how you would use a library like Floating UI.
  5. Cleanup: Close the popover when the user presses Esc or clicks outside.

Interface

function Popover({ triggerId, fetchData }) {
  // fetchData is a function returning a Promise
  // triggerId is a unique identifier
}

Examples

  • Triggering: Clicking "Load User A" renders a popover at the button's coordinates, displays a spinner, and eventually renders the user profile.
  • Keyboard: Pressing Tab moves focus to the button; pressing Enter opens the popover. Pressing Esc closes it and returns focus to the button.

Constraints

  • Assume standard browser support.
  • Handle errors gracefully if fetchData fails.

Hints

Hint 1

Use a unique `id` for the popover content and link it to the button using `aria-controls` for screen reader navigation.

Hint 2

Implement a 'request ID' or an abort controller within the hook to ignore stale responses that resolve after a newer request has started.

Hint 3

Use a React Portal to render the popover in the document body to prevent z-index and overflow clipping issues.

Follow-up questions

  • How would you optimize performance if you have 1,000 buttons on the page, each needing this functionality?
  • How would you handle focus restoration if the button that triggered the popover is removed from the DOM while the popover is still open?
  • Describe how you would unit test the 'stale-response' scenario using a testing library like Jest or Vitest.