Skip to content

Virtualized List ​

Demonstrates smooth 60fps scrolling with 10,000 items using the built-in virtualizer. No configuration is required -- virtualization activates automatically when filtered results exceed 100 items.

10K Items ​

tsx
'use client';

import { Command } from 'modern-cmdk/react';

// Generate 10,000 items
const categories = ['General', 'Account', 'Finance', 'Data', 'Security'];
const labels = ['Settings', 'Profile', 'Billing', 'Analytics', 'Security'];
const items = Array.from({ length: 10_000 }, (_, i) => ({
  id: `item-${i}`,
  label: `Item ${i} -- ${labels[i % 5]}`,
  value: `item-${i}`,
  category: categories[i % 5]!,
}));

export function VirtualizedExample() {
  return (
    <Command label="Large Dataset">
      <Command.Input placeholder="Search 10,000 items..." />
      <Command.List estimateSize={44} overscan={10}>
        <Command.Empty>No results.</Command.Empty>
        {items.map((item) => (
          <Command.Item
            key={item.id}
            value={item.value}
            keywords={[item.category]}
            onSelect={() => console.log('Selected:', item.id)}
          >
            {item.label}
            <Command.Badge>{item.category}</Command.Badge>
          </Command.Item>
        ))}
      </Command.List>
    </Command>
  );
}

Custom Configuration ​

Tune the virtualizer for your specific use case:

tsx
import { Command } from 'modern-cmdk/react';

export function TunedList() {
  return (
    <Command label="Tuned virtualizer">
      <Command.List
        estimateSize={64} // Taller items (64px estimated height)
        overscan={15} // More overscan for fast scrolling
      >
        {/* items */}
      </Command.List>
    </Command>
  );
}
PropTypeDefaultDescription
estimateSizenumber44Estimated item height (px) before measurement
overscannumber8Extra items rendered beyond the viewport
virtualizebooleanunset (auto)Unset: virtualizes above 100 filtered items and stops again at 50 or fewer. true forces it on; false disables it

Opting Out ​

If you need all items in the DOM (e.g., for custom scroll behavior):

tsx
import { Command } from 'modern-cmdk/react';

export function UnvirtualizedList() {
  return (
    <Command label="All items in the DOM">
      <Command.List virtualize={false}>
        {/* All items render in the DOM */}
      </Command.List>
    </Command>
  );
}

WARNING

Disabling virtualization with 1K+ items will significantly impact performance.

Performance CSS ​

Add these styles for additional rendering optimization:

css
[data-command-item] {
  content-visibility: auto;
  contain-intrinsic-size: auto 44px;
  contain: layout style paint;
}

[data-command-list] {
  will-change: transform;
}

The WASM search engine is an unpublished, build-from-source package (see modern-cmdk-search-wasm). To pair it with virtualization:

tsx
'use client';

import { Command } from 'modern-cmdk/react';
import { createWasmSearchEngine, type FallbackSearchEngine, type WasmSearchEngine } from 'modern-cmdk-search-wasm';
import { useEffect, useState } from 'react';

// The factory resolves to the WASM engine or the TypeScript fallback engine (both types are exported)
type WasmEngine = WasmSearchEngine | FallbackSearchEngine;

const items = Array.from({ length: 10_000 }, (_, i) => ({
  id: `item-${i}`,
  label: `Item ${i}`,
  value: `item-${i}`,
}));

export function WasmVirtualizedExample() {
  const [engine, setEngine] = useState<WasmEngine | null>(null);

  useEffect(() => {
    let wasmEngine: WasmEngine | null = null;
    async function init() {
      wasmEngine = await createWasmSearchEngine();
      setEngine(wasmEngine);
    }
    init();
    return () => { wasmEngine?.[Symbol.asyncDispose](); };
  }, []);

  if (!engine) return <div>Loading search engine...</div>;

  return (
    <Command search={engine} label="WASM + Virtual">
      <Command.Input placeholder="Fuzzy search 10K items..." />
      <Command.List estimateSize={44} overscan={10}>
        <Command.Empty>No results.</Command.Empty>
        {items.map((item) => (
          <Command.Item key={item.id} value={item.value} onSelect={() => {}}>
            {item.label}
          </Command.Item>
        ))}
      </Command.List>
    </Command>
  );
}