cmdk icon indicating copy to clipboard operation
cmdk copied to clipboard

TypeError after copying a working example, trying to read subscribe from undefined

Open mastoj opened this issue 10 months ago • 4 comments

I get the TypeError: Cannot read properties of undefined (reading 'subscribe') in my simple experiment.

I've copied the code from shadcn, but for some reason it does not work.

Below is my command component, and I can't see anything weird with it.

"use client";

import { type DialogProps } from "@radix-ui/react-dialog";
import { Command as CommandPrimitive } from "cmdk";
import { Search } from "lucide-react";
import * as React from "react";
import { cn } from "../@shadcn-lib";
import { Dialog, DialogContent } from "./dialog";

const Command = React.forwardRef<
  React.ElementRef<typeof CommandPrimitive>,
  React.ComponentPropsWithoutRef<typeof CommandPrimitive>
>(({ className, ...props }, ref) => {
  return (
    <CommandPrimitive
      ref={ref}
      className={cn(
        "flex h-full w-full flex-col overflow-hidden rounded-md bg-popover text-popover-foreground",
        className,
      )}
      {...props}
    />
  );
});

Command.displayName = CommandPrimitive.displayName;

const CommandDialog = ({ children, ...props }: DialogProps) => {
  return (
    <Dialog {...props}>
      <DialogContent className="overflow-hidden p-0 shadow-lg">
        <Command className="[&_[cmdk-group-heading]]:px-2 [&_[cmdk-group-heading]]:font-medium [&_[cmdk-group-heading]]:text-muted-foreground [&_[cmdk-group]:not([hidden])_~[cmdk-group]]:pt-0 [&_[cmdk-group]]:px-2 [&_[cmdk-input-wrapper]_svg]:h-5 [&_[cmdk-input-wrapper]_svg]:w-5 [&_[cmdk-input]]:h-12 [&_[cmdk-item]]:px-2 [&_[cmdk-item]]:py-3 [&_[cmdk-item]_svg]:h-5 [&_[cmdk-item]_svg]:w-5">
          {children}
        </Command>
      </DialogContent>
    </Dialog>
  );
};

const CommandInput = React.forwardRef<
  React.ElementRef<typeof CommandPrimitive.Input>,
  React.ComponentPropsWithoutRef<typeof CommandPrimitive.Input>
>(({ className, ...props }, ref) => (
  // eslint-disable-next-line react/no-unknown-property
  <div className="flex items-center border-b px-3" cmdk-input-wrapper="">
    <Search className="mr-2 h-4 w-4 shrink-0 opacity-50" />
    <CommandPrimitive.Input
      ref={ref}
      className={cn(
        "flex h-11 w-full rounded-md bg-transparent py-3 text-sm outline-none placeholder:text-muted-foreground disabled:cursor-not-allowed disabled:opacity-50",
        className,
      )}
      {...props}
    />
  </div>
));

CommandInput.displayName = CommandPrimitive.Input.displayName;

const CommandList = React.forwardRef<
  React.ElementRef<typeof CommandPrimitive.List>,
  React.ComponentPropsWithoutRef<typeof CommandPrimitive.List>
>(({ className, ...props }, ref) => (
  <CommandPrimitive.List
    ref={ref}
    className={cn("max-h-[300px] overflow-y-auto overflow-x-hidden", className)}
    {...props}
  />
));

CommandList.displayName = CommandPrimitive.List.displayName;

const CommandEmpty = React.forwardRef<
  React.ElementRef<typeof CommandPrimitive.Empty>,
  React.ComponentPropsWithoutRef<typeof CommandPrimitive.Empty>
>((props, ref) => (
  <CommandPrimitive.Empty
    ref={ref}
    className="py-6 text-center text-sm"
    {...props}
  />
));

CommandEmpty.displayName = CommandPrimitive.Empty.displayName;

const CommandGroup = React.forwardRef<
  React.ElementRef<typeof CommandPrimitive.Group>,
  React.ComponentPropsWithoutRef<typeof CommandPrimitive.Group>
>(({ className, ...props }, ref) => (
  <CommandPrimitive.Group
    ref={ref}
    className={cn(
      "overflow-hidden p-1 text-foreground [&_[cmdk-group-heading]]:px-2 [&_[cmdk-group-heading]]:py-1.5 [&_[cmdk-group-heading]]:text-xs [&_[cmdk-group-heading]]:font-medium [&_[cmdk-group-heading]]:text-muted-foreground",
      className,
    )}
    {...props}
  />
));

CommandGroup.displayName = CommandPrimitive.Group.displayName;

const CommandSeparator = React.forwardRef<
  React.ElementRef<typeof CommandPrimitive.Separator>,
  React.ComponentPropsWithoutRef<typeof CommandPrimitive.Separator>
>(({ className, ...props }, ref) => (
  <CommandPrimitive.Separator
    ref={ref}
    className={cn("-mx-1 h-px bg-border", className)}
    {...props}
  />
));
CommandSeparator.displayName = CommandPrimitive.Separator.displayName;

const CommandItem = React.forwardRef<
  React.ElementRef<typeof CommandPrimitive.Item>,
  React.ComponentPropsWithoutRef<typeof CommandPrimitive.Item>
>(({ className, ...props }, ref) => (
  <CommandPrimitive.Item
    ref={ref}
    className={cn(
      "relative flex cursor-default gap-2 select-none items-center rounded-sm px-2 py-1.5 text-sm outline-none data-[disabled=true]:pointer-events-none data-[selected='true']:bg-accent data-[selected=true]:text-accent-foreground data-[disabled=true]:opacity-50 [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0",
      className,
    )}
    {...props}
  />
));

CommandItem.displayName = CommandPrimitive.Item.displayName;

const CommandShortcut = ({
  className,
  ...props
}: React.HTMLAttributes<HTMLSpanElement>) => {
  return (
    <span
      className={cn(
        "ml-auto text-xs tracking-widest text-muted-foreground",
        className,
      )}
      {...props}
    />
  );
};
CommandShortcut.displayName = "CommandShortcut";

const CommandLoading = React.forwardRef<
  React.ElementRef<typeof CommandPrimitive.Loading>,
  React.ComponentPropsWithoutRef<typeof CommandPrimitive.Loading>
>(({ className, ...props }, ref) => (
  <CommandPrimitive.Loading
    ref={ref}
    className={cn("px-2 py-1.5 text-center text-sm", className)}
    {...props}
  />
));

CommandLoading.displayName = CommandPrimitive.Loading.displayName;

export {
  Command,
  CommandDialog,
  CommandEmpty,
  CommandGroup,
  CommandInput,
  CommandItem,
  CommandList,
  CommandLoading,
  CommandSeparator,
  CommandShortcut,
};

I then use it like so:


import { suggestAction } from "@domains/search/search-actions";
import {
  Command,
  CommandEmpty,
  CommandGroup,
  CommandItem,
  CommandList,
} from "@repo/ui/command";
import { cn } from "@repo/ui/shadcn-lib";
import { useDebounce } from "@utils/helper-hooks";
import { SiteContext } from "@utils/service-types";
import { CommandLoading, Command as CommandPrimitive } from "cmdk";
import { LoaderCircle } from "lucide-react";
import {
  KeyboardEventHandler,
  useEffect,
  useRef,
  useState,
  useTransition,
} from "react";

interface SuggestAutoCompleteProps {
  onSubmit?: () => void;
  className?: string;
  siteContext: SiteContext;
}

export function SuggestAutoComplete({
  onSubmit,
  className,
  siteContext,
}: SuggestAutoCompleteProps) {
  const [open, setOpen] = useState(false);
  const [isPending, startTransition] = useTransition();
  const [items, setItems] = useState<{ value: string; label: string }[]>([]);
  const [search, setSearch] = useState("");
  const debouncedSearch = useDebounce(search, 300);
  const inputRef = useRef<HTMLInputElement>(null);

  useEffect(() => {
    if (debouncedSearch) {
      startTransition(async () => {
        const data = await suggestAction(siteContext, debouncedSearch);
        if (data.success) {
          setItems(
            data.data.map((d) => ({
              label: d.name,
              value: d.href ?? d.name,
            })),
          );
        }
      });
    } else {
      setItems([]);
    }
  }, [debouncedSearch, siteContext]);

  const handleKeyDown: KeyboardEventHandler<HTMLInputElement> = (event) => {
    if (event.key === "Escape") {
      inputRef.current?.blur();
    }
  };

  function handleSelect(currentValue: string) {
    startTransition(async () => {
      setSearch(currentValue);
      inputRef.current?.blur();
      onSubmit?.();
    });
  }

  return (
    <Command shouldFilter={false} className="overflow-visible">
      <CommandPrimitive.Input
        ref={inputRef}
        placeholder="Search products"
        value={search}
        onInput={(e) => setSearch(e.currentTarget.value)}
        onKeyDown={handleKeyDown}
        onFocus={() => setOpen(true)}
        onBlur={() => setOpen(false)}
        className={cn(
          "flex h-10 w-full rounded-md border border-input bg-transparent px-3 py-2 text-sm ring-offset-background file:border-0 file:bg-transparent file:text-sm file:font-medium placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50",
          "placeholder:font-light",
          className,
        )}
      />
      <div className="relative">
        {open && debouncedSearch ? (
          <CommandList className="absolute top-1.5 z-50 w-full rounded-md border border-border bg-background">
            {isPending ? (
              <CommandLoading>
                <LoaderCircle className="h-4 w-4 animate-spin text-muted-foreground" />
              </CommandLoading>
            ) : (
              <>
                <CommandEmpty>No results.</CommandEmpty>
                <CommandGroup>
                  {items.map((item, i) => {
                    const [first, rest] = item.label.split(/,(.+)/);
                    return (
                      <CommandItem
                        key={`${item.value}-${item.label}-${i}`}
                        value={item.value}
                        onSelect={handleSelect}
                        onMouseDown={(e) => {
                          e.preventDefault();
                          e.stopPropagation();
                        }}
                        className="flex gap-1 truncate items-baseline"
                      >
                        <span key={first}>{first}</span>{" "}
                        <span
                          key={rest}
                          className="truncate text-xs text-muted-foreground"
                        >
                          {rest}
                        </span>
                      </CommandItem>
                    );
                  })}
                </CommandGroup>
              </>
            )}
          </CommandList>
        ) : null}
      </div>
    </Command>
  );
}

Nothing to fancy at all as I see it. Any known causes to the error I see and how to fix?

mastoj avatar Feb 27 '25 08:02 mastoj

I had a very similar error, but mine was because I accidentally imported an icon called "Command". Try swapping out components of the shadcn lib for barebones cmdk components until something starts working or double check your imports.

bvincent1 avatar Mar 26 '25 00:03 bvincent1

bump

z0xca avatar Apr 03 '25 21:04 z0xca

https://github.com/shadcn-ui/ui/issues/1939#issuecomment-1826720441 Hope this helps you

lyratu avatar Apr 08 '25 08:04 lyratu

@bvincent1, you are my hero! After a couple of hours, your tip saved my day.

giolvani avatar Aug 08 '25 02:08 giolvani