Skip to content

The first item is not selected by default when Command.List content is dynamic #280

Open
@jaxxreal

Description

Issue description

When content of Command.List is dynamic eg rendering result of a search API endpoint results the first item is not always selected by default.

In case I am doing something wrong, please let me know.

Setup

shadcn's Command component, cmdk@1.0.0

Repro

Repro steps for stackblitz template I drafted up.

Expected:

  1. Type "air" in the input
  2. When results appear, the first item is highlighted
  3. When no results and Add <query> item appears - it's highlighted since it's the first item in the list

Actual:

  1. Type "air" in the input
  2. When results appear, the first item is NOT highlighted
  3. When no results appear and Add <query> item appears - it's NOT highlighted

EDIT: bringing code sample here, just in case

import { Command, CommandInput, CommandItem, CommandList } from './Command';

export default function App() {
  const [items, setItems] = React.useState([]);
  const [isLoading, setIsLoading] = React.useState(false);
  const [q, setQ] = React.useState('');

  const hasSearchResults = items.length > 0;

  React.useEffect(() => {
    if (!q) {
      return;
    }

    setItems([]);
    setIsLoading(true);

    setTimeout(() => {
      setItems(
        dataArray
          .filter((v) => v.includes(q.toLocaleLowerCase()))
          .map((v, idx) => ({
            name: v,
            id: v + idx,
            onSelect: (value: string) => {
              console.log('Selection was made:', value);
            },
          }))
      );
      setIsLoading(false);
    }, 2000);
  }, [q]);

  return (
    <>
      <h1 className="text-3xl font-bold underline">
        First item default selection issue
      </h1>
      <div>
        <Command
          className="rounded-lg border shadow-md"
          shouldFilter={false}
          loop
        >
          <CommandInput placeholder={'Search...'} onValueChange={setQ} />
          <CommandList className="h-fit">
            {isLoading && (
              <CommandItem key={'spinner'} forceMount>
                Searching...
              </CommandItem>
            )}

            {hasSearchResults &&
              items.map((item) => {
                return <RecordCommandItem key={item.id} {...item} />;
              })}

            {!hasSearchResults && !isLoading && q.length > 0 && (
              <CommandItem
                forceMount
                key="create-new-record"
                value={q}
                onMouseDown={(e) => {
                  e.preventDefault();
                  e.stopPropagation();
                }}
                onSelect={(value: string) => {
                  setQ('');
                  console.log('Created!');
                }}
              >
                {`Add "${q}"`}
              </CommandItem>
            )}
          </CommandList>
        </Command>
      </div>
    </>
  );
}

interface RecordCommandItemProps {
  name: string;
  description: string;
  id: string;
  onSelect: (value: string) => void;
}

function RecordCommandItem({
  name,
  description,
  id,
  onSelect,
}: RecordCommandItemProps) {
  return (
    <CommandItem value={id} onSelect={onSelect}>
      <div className="flex flex-row gap-2 text-sm">
        <div className="font-medium">{name}</div>
        <div className="capitalize text-gray-500">{description}</div>
        <span hidden>{id}</span>
      </div>
    </CommandItem>
  );
}

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions