Home

Search without re-rendering the list.

React usually filters by deriving a new array and reconciling a new list. React Zero-UI can keep the rows mounted, flip data-* attributes, and let CSS hide the non-matches.

Type a search in both panes and switch categories. React re-renders the list; Zero-UI just toggles visibility.

React useState

Search and category live in React state, every keystroke re-renders this pane. O(n) re-renders.

Renders: 4

10 results visible

  • Laptop Pro 14"
    electronics
    $1299
  • Noise-cancelling Headphones
    electronics
    $299
  • Wireless Mouse
    electronics
    $49
  • 4K Monitor
    electronics
    $449
  • Mechanical Keyboard
    electronics
    $129
  • The Pragmatic Programmer
    books
    $32
  • Designing Data-Intensive Apps
    books
    $45
  • Refactoring
    books
    $38
  • Clean Code
    books
    $29
  • Merino Wool Sweater
    clothing
    $89

Zero re-render Search & Filter

Search mode, category, and empty state flip data-* attrs; rows stay mounted. Zero re-renders.

Renders: 1

10 results visible

  • Laptop Pro 14"
    electronics
    $1299
  • Noise-cancelling Headphones
    electronics
    $299
  • Wireless Mouse
    electronics
    $49
  • 4K Monitor
    electronics
    $449
  • Mechanical Keyboard
    electronics
    $129
  • The Pragmatic Programmer
    books
    $32
  • Designing Data-Intensive Apps
    books
    $45
  • Refactoring
    books
    $38
  • Clean Code
    books
    $29
  • Merino Wool Sweater
    clothing
    $89

Type in either search box or change a category. The React pane filters by rendering a new list. The Zero-UI pane keeps the full list mounted and flips attributes so CSS handles visibility.

The code that matters

const [mode, setMode] = useScopedUI('filter-search', 'idle');function search(query: string) {  setMode(query ? 'active' : 'idle');  rows.forEach((row) => {    row.dataset.searchMatch =      row.dataset.searchText?.includes(query)        ? 'true'        : 'false';  });}<div ref={setMode.ref} data-filter-search={mode}><li  data-search-match="true"  className="filter-search-active:data-[search-match=false]:hidden"/></div>

When to reach for this

  • - The list is already loaded and filtering is purely presentational.
  • - Search text is unbounded, so JS marks matching rows.
  • - Finite UI states like active search, category, and empty state flip data attributes.
  • - The expensive tree stays mounted while CSS controls visibility.