Performance
medium
mid
If an API returns 5000 records, how do you display them efficiently in a dropdown?
Don't render 5000 DOM nodes. Combine: server-side search/pagination, async incremental load, virtualization (react-window / TanStack Virtual), and a debounced filter input. Most apps need only the last three; large lists need all four.
7 min read·~25 min to think through
Rendering 5000 <option> or <li> nodes destroys layout/paint and is unusable on mobile. The combined fix:
- Search-first, list-second. Most users want one of a handful of items. Render an input that filters the list — the dropdown only shows ~20 matches. Combobox UX (downshift, headlessui Combobox) is the right primitive.
- Virtualization. Even with filtering, the worst case is "no filter" — 5000 rows. Render only the visible window plus a small overscan. Use
react-windowor@tanstack/react-virtual. - Server-side pagination/search. If the dataset can grow, push search to the server and stream the next page on scroll. Don't bring 5000 back to the client when you'll show 20.
- Debounce input. 200–300ms keeps typing fluid; without it you re-filter 5000 records per keystroke.
- Index for fast filter. A pre-built lowercased index avoids
.toLowerCase()on every keystroke. Fuse.js for fuzzy search. - Accessibility. Combobox needs proper ARIA:
role="combobox",aria-expanded,aria-activedescendant, keyboard navigation. Custom dropdowns lose this routinely.
Mobile considerations: native <select> is faster than any custom dropdown for simple cases — use it unless the design requires custom rendering.
Code
Follow-up questions
- •How does virtualization affect screen-reader navigation, and how do you mitigate it?
- •When is an HTML <select> better than a custom combobox?
- •How would you implement multi-select with the same constraints?
Common mistakes
- •Trusting the design and rendering 5000 nodes — okay on desktop, dies on mobile.
- •Filtering on the client when the dataset can grow without bound.
- •Building a custom dropdown without ARIA, breaking screen readers.
Performance considerations
- •Virtualization keeps DOM size bounded; CPU per scroll is overscan + visible count.
- •Filtering 5000 strings is fast; what kills perf is recreating React subtrees per keystroke without virtualization.
Edge cases
- •Variable-height rows — use `dynamicSizeList` (react-window) or the `measureElement` API in TanStack Virtual.
- •Selected option scroll-into-view on open — call `scrollToIndex` after mount.
Real-world examples
- •Linear's combobox, GitHub's user-picker, and Notion's mention menu are all virtualized + server-search comboboxes.
Senior engineer discussion
Senior signal: discuss tradeoffs between client-side filtering (instant) and server-side search (scales), ARIA combobox patterns, and how IME composition affects keystroke handling on East Asian inputs.
Related questions
Performance
Medium
7 min