[bug]: Combo box is not working.
akeakun opened this issue ยท 12 comments
Describe the bug
the default code for combobox in a next.js app throws this error:
Unhandled Runtime Error
TypeError: undefined is not iterable (cannot read property Symbol(Symbol.iterator))
Affected component/components
ComboBox
How to reproduce
just copy the default code for combo box from shadcnui.com/combobox and paste it in page.tsx
run the code and the error should pop up while trying to click the PopoverTrigger button.
Codesandbox/StackBlitz link
No response
Logs
No response
System Info
browser
Before submitting
- I've made research efforts and searched the documentation
- I've searched for existing issues
maybe the cmdk package has some changes and the shadcnui not response to.
you need to use this version, v1 doesnt work
"cmdk": "^0.2.1",
or
tailwind.config.ts
plugins: [
require("tailwindcss-animate"),
function ({ addUtilities }) {
addUtilities({
".popover-content-width-same-as-its-trigger": {
width: "var(--radix-popover-trigger-width)",
"max-height": "var(--radix-popover-content-available-height)",
},
});
},
],
my-combobox.tsx
type MyComboboxProps = {
label?: string;
value: string;
setValue: (value: string) => void;
values: { label: string; value: string }[];
inputDisabled?: boolean;
inputPlaceholder?: string;
};
export const MyCombobox: React.FC<MyComboboxProps> = (props) => {
const [open, setOpen] = useState(false);
return (
<Popover open={open} onOpenChange={setOpen}>
<div className="flex flex-col w-full">
{props.label && <Label className="mb-1">{props.label}</Label>}
<PopoverTrigger asChild>
<Button
variant="outline"
role="combobox"
aria-expanded={open}
className=" justify-between"
>
{props.value
? props.values.find((item) => item.value === props.value)?.label
: props.label + "..."}
<ChevronsUpDown className="ml-2 h-4 w-4 shrink-0 opacity-50" />
</Button>
</PopoverTrigger>
</div>
<PopoverContent
className={"popover-content-width-same-as-its-trigger p-0"}
>
<Command>
{props.inputDisabled && (
<CommandInput placeholder={props.inputPlaceholder} />
)}
<CommandEmpty>NOTHING_FOUND</CommandEmpty>
<CommandGroup>
<CommandList>
{props.values.map((item) => (
<CommandItem
key={item.value}
value={item.value}
onSelect={(currentValue) => {
props.setValue(
currentValue === props.value ? "" : currentValue
);
setOpen(false);
}}
>
<Check
className={cn(
"mr-2 h-4 w-4",
props.value === item.value ? "opacity-100" : "opacity-0"
)}
/>
{item.label}
</CommandItem>
))}
</CommandList>
</CommandGroup>
</Command>
</PopoverContent>
</Popover>
);
};
you need to use this version, v1 doesnt work
"cmdk": "^0.2.1",
Great catch, once downgrading I no longer run into the issue.
Just wrap CommandGroup
in a CommandList
and it will work on latest cmdk
. Move the CommandEmpty
inside as well.
It should look like this: (just command, popover stuff removed for brevity)
<Command>
<CommandInput placeholder="Search ..." />
<CommandList>
<CommandEmpty>No option found.</CommandEmpty>
<CommandGroup>
{options.map((option) => {
return (
<CommandItem
key={option.value}
value={option.value}
onSelect={(currentValue) => {
setValue(currentValue === value ? "" : currentValue);
setOpen(false);
onValueChange(currentValue);
}}
>
<CheckIcon
className={cn(
"mr-2 h-4 w-4",
value === option.value ? "opacity-100" : "opacity-0",
)}
/>
{option.label}
</CommandItem>
);
})}
</CommandGroup>
</CommandList>
</Command>
you need to use this version, v1 doesnt work
"cmdk": "^0.2.1",
Weekend saved, nice catch
Yo bro, the command box may not be working for 2 reasons.
- You didnt wrap the CommantGroup or CommandItem with the CommandList, its required with the current relaease as of this date.
- The exact issue i had struggled with for over 6hours. Go to your Command component, and paste the code below to overwrite the default. Or simply replace every className with data-[disabled] to data-[disabled=true].
"use client";
import * as React from "react";
import { type DialogProps } from "@radix-ui/react-dialog";
import { MagnifyingGlassIcon } from "@radix-ui/react-icons";
import { Command as CommandPrimitive } from "cmdk";
import { cn } from "@/lib/utils";
import { Dialog, DialogContent } from "@/components/ui/dialog";
const Command = React.forwardRef<
React.ElementRef,
React.ComponentPropsWithoutRef
(({ className, ...props }, ref) => (
<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;
interface CommandDialogProps extends DialogProps {}
const CommandDialog = ({ children, ...props }: CommandDialogProps) => {
return (
<Dialog {...props}>
{children}
);
};
const CommandInput = React.forwardRef<
React.ElementRef,
React.ComponentPropsWithoutRef
(({ className, ...props }, ref) => (
CommandInput.displayName = CommandPrimitive.Input.displayName;
const CommandList = React.forwardRef<
React.ElementRef,
React.ComponentPropsWithoutRef
(({ 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,
React.ComponentPropsWithoutRef
((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,
React.ComponentPropsWithoutRef
(({ 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,
React.ComponentPropsWithoutRef
(({ 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,
React.ComponentPropsWithoutRef
(({ className, ...props }, ref) => (
<CommandPrimitive.Item
ref={ref}
className={cn(
"relative flex cursor-default select-none items-center rounded-sm px-2 py-1.5 text-sm outline-none aria-selected:bg-accent aria-selected:text-accent-foreground data-[disabled=true]:pointer-events-none data-[disabled=true]:opacity-50",
className
)}
{...props}
/>
));
CommandItem.displayName = CommandPrimitive.Item.displayName;
const CommandShortcut = ({
className,
...props
}: React.HTMLAttributes) => {
return (
<span
className={cn(
"ml-auto text-xs tracking-widest text-muted-foreground",
className
)}
{...props}
/>
);
};
CommandShortcut.displayName = "CommandShortcut";
export {
Command,
CommandDialog,
CommandInput,
CommandList,
CommandEmpty,
CommandGroup,
CommandItem,
CommandShortcut,
CommandSeparator,
};
Just wrap
CommandGroup
in aCommandList
and it will work on latestcmdk
. Move theCommandEmpty
inside as well.It should look like this: (just command, popover stuff removed for brevity)
<Command> <CommandInput placeholder="Search ..." /> <CommandList> <CommandEmpty>No option found.</CommandEmpty> <CommandGroup> {options.map((option) => { return ( <CommandItem key={option.value} value={option.value} onSelect={(currentValue) => { setValue(currentValue === value ? "" : currentValue); setOpen(false); onValueChange(currentValue); }} > <CheckIcon className={cn( "mr-2 h-4 w-4", value === option.value ? "opacity-100" : "opacity-0", )} /> {option.label} </CommandItem> ); })} </CommandGroup> </CommandList> </Command>
Thanks man.