# Async loading

> Debounced search with skeleton rows while loading, an empty state, and shouldFilter disabled for server-driven results.

A shadcn/ui block from the [@flx](https://ui.flexnative.com) registry, listed on [shadcn.exchange](https://shadcn.exchange/r/flx/command-04).

- Page, with a live preview: https://shadcn.exchange/r/flx/command-04
- Screenshot: https://abzjhwgwpdpz7ua5.public.blob.vercel-storage.com/shots/flx/command-04-light-70286b85fb60bc44.png
- Registry item: https://ui.flexnative.com/r/command-04.json
- Listed: 2026-10-13, source last changed 2026-10-13

## Install

```bash
npx shadcn@latest add https://ui.flexnative.com/r/command-04.json
```

Run it in a project that has shadcn/ui set up. It adds the files below and installs what they depend on.

## Dependencies

- Registry items: `command`

## Files

### `registry/patterns/command/command-04.tsx`

```tsx
'use client'

import {
  Command,
  CommandGroup,
  CommandInput,
  CommandItem,
  CommandList,
} from '@/components/ui/command'
import { PackageIcon, SearchXIcon, TrendingUpIcon } from 'lucide-react'
import { useEffect, useState } from 'react'

const registry = [
  'react',
  'react-dom',
  'radix-ui',
  'tailwindcss',
  'typescript',
  'next',
  'zod',
]

const popular = ['react', 'next', 'tailwindcss']
const skeletonWidths = ['58%', '44%', '66%']

export function Command04() {
  const [query, setQuery] = useState('')
  const [loading, setLoading] = useState(false)
  const [results, setResults] = useState<string[]>([])

  useEffect(() => {
    if (!query.trim()) {
      setResults([])
      setLoading(false)
      return
    }
    setLoading(true)
    const id = setTimeout(() => {
      setResults(
        registry.filter((item) => item.includes(query.toLowerCase().trim())),
      )
      setLoading(false)
    }, 600)
    return () => clearTimeout(id)
  }, [query])

  return (
    <Command
      shouldFilter={false}
      className="size-auto w-full max-w-md rounded-lg border shadow-sm"
    >
      <CommandInput
        placeholder="Search npm packages..."
        value={query}
        onValueChange={setQuery}
      />
      <CommandList className="min-h-32">
        {loading &&
          skeletonWidths.map((width, index) => (
            <div
              key={index}
              className="flex items-center gap-2 px-3 py-2"
              aria-hidden
            >
              <div className="bg-muted size-4 shrink-0 animate-pulse rounded" />
              <div
                className="bg-muted h-3 animate-pulse rounded"
                style={{ width }}
              />
            </div>
          ))}

        {!loading && !query.trim() && (
          <CommandGroup heading="Popular">
            {popular.map((item) => (
              <CommandItem key={item} value={item}>
                <TrendingUpIcon />
                <span>{item}</span>
              </CommandItem>
            ))}
          </CommandGroup>
        )}

        {!loading && query.trim() && results.length === 0 && (
          <div className="text-muted-foreground flex flex-col items-center gap-1.5 py-8 text-sm">
            <SearchXIcon className="size-5 opacity-50" />
            No packages match “{query.trim()}”.
          </div>
        )}

        {!loading && results.length > 0 && (
          <CommandGroup heading="Results">
            {results.map((item) => (
              <CommandItem key={item} value={item}>
                <PackageIcon />
                <span>{item}</span>
              </CommandItem>
            ))}
          </CommandGroup>
        )}
      </CommandList>
    </Command>
  )
}
```
