We use cookies for site analytics. Accept to help us understand how the site is used. See our Privacy Policy for details.
A medium frontend problem, graded against 5 test cases (2 of them hidden).
React and browser-platform problems - hooks, event handling, and rendering behaviour.
Reach for it when you see: A component, hook, or DOM-behaviour question rather than an algorithm.
More Frontendproblems →```tsx
function TodoList({ todos, onToggle }: { todos: Todo[]; onToggle: (id: string) => void }) {
function handleClick(e: React.MouseEvent) {
const target = (e.target as HTMLElement).closest<HTMLElement>("[data-todo-id]");
if (!target) return;
onToggle(target.dataset.todoId!);
}
return (
<ul onClick={handleClick}>
{todos.map(t => (
<li key={t.id} data-todo-id={t.id}>{t.label}</li>
))}
</ul>
);
}
```
Why event delegation wins:
- One listener instead of N. For a 10,000-row table, the saving is real - both memory and the cost of attaching/detaching on virtualized scroll.
- Newly-added children automatically participate - no need to re-bind.
- Pairs naturally with data attributes for IDs.
`closest(selector)` walks up the DOM tree (including the element itself) and returns the first ancestor matching `selector`, or null. This is exactly the algorithm you implemented for the auto-grader.
When NOT to delegate: for events that don't bubble (`focus`, `blur`, `mouseenter`, `mouseleave`, `load`). For those, use the bubbling alternatives (`focusin`, `focusout`, `mouseover`, `mouseout`) or attach per-element.
The full reference solution in every supported language stays in the editor above - reveal it there once you have had a real attempt.
Read off this problem's own test suite, so these are the cases a submission actually has to survive.
These apply to the pattern as a whole, not just this problem.