shadcn-ui / ui

Beautifully designed components that you can copy and paste into your apps. Accessible. Customizable. Open Source.
https://ui.shadcn.com
MIT License
70.65k stars 4.24k forks source link

[bug]: Combobox inside Form Component in docs is not working as expected. #4117

Open leooism opened 3 months ago

leooism commented 3 months ago

Describe the bug

When clicking the combobox the error in the console is.

TypeError: undefined is not iterable (cannot read property Symbol(Symbol.iterator)) at Function.from () at O (69016-e46275a046c77977.js:1:8485) at M (69016-e46275a046c77977.js:1:7484) at 69016-e46275a046c77977.js:1:6256 at 69016-e46275a046c77977.js:1:14852 at Map.forEach () at 69016-e46275a046c77977.js:1:14841 at aI (eb2a38ac-8c1a930f3b668d8a.js:1:72883) at aU (eb2a38ac-8c1a930f3b668d8a.js:1:72943) at aV (eb2a38ac-8c1a930f3b668d8a.js:1:73382).

Affected component/components

Combobox

How to reproduce

  1. Go to combobox component in the docs
  2. The final example, a combobox inside form component.
  3. Click the combobox

Codesandbox/StackBlitz link

No response

Logs

TypeError: undefined is not iterable (cannot read property Symbol(Symbol.iterator))
    at Function.from (<anonymous>)
    at O (69016-e46275a046c77977.js:1:8485)
    at M (69016-e46275a046c77977.js:1:7484)
    at 69016-e46275a046c77977.js:1:6256
    at 69016-e46275a046c77977.js:1:14852
    at Map.forEach (<anonymous>)
    at 69016-e46275a046c77977.js:1:14841
    at aI (eb2a38ac-8c1a930f3b668d8a.js:1:72883)
    at aU (eb2a38ac-8c1a930f3b668d8a.js:1:72943)
    at aV (eb2a38ac-8c1a930f3b668d8a.js:1:73382)

System Info

Browser

Before submitting

mboultoureau commented 3 months ago

Hi, as mentioned in ticket #4106, this happens because the CommandList component is missing around CommandEmpty and CommandGroup. Here's how to change the code (green lines). You can also look at the other examples that don't have this oversight.

"use client"

import { zodResolver } from "@hookform/resolvers/zod"
import { Check, ChevronsUpDown } from "lucide-react"
import { useForm } from "react-hook-form"
import { z } from "zod"

import { Button } from "@/components/ui/button"
import {
  Command,
  CommandEmpty,
  CommandGroup,
  CommandInput,
  CommandItem,
+ CommandList,
} from "@/components/ui/command"
import {
  Form,
  FormControl,
  FormDescription,
  FormField,
  FormItem,
  FormLabel,
  FormMessage,
} from "@/components/ui/form"
import {
  Popover,
  PopoverContent,
  PopoverTrigger,
} from "@/components/ui/popover"
import { toast } from "@/components/ui/use-toast"
import { cn } from "@/lib/utils"

const languages = [
  { label: "English", value: "en" },
  { label: "French", value: "fr" },
  { label: "German", value: "de" },
  { label: "Spanish", value: "es" },
  { label: "Portuguese", value: "pt" },
  { label: "Russian", value: "ru" },
  { label: "Japanese", value: "ja" },
  { label: "Korean", value: "ko" },
  { label: "Chinese", value: "zh" },
] as const

const FormSchema = z.object({
  language: z.string({
    required_error: "Please select a language.",
  }),
})

export default function ComboboxForm() {
  const form = useForm<z.infer<typeof FormSchema>>({
    resolver: zodResolver(FormSchema),
  })

  function onSubmit(data: z.infer<typeof FormSchema>) {
    toast({
      title: "You submitted the following values:",
      description: (
        <pre className="mt-2 w-[340px] rounded-md bg-slate-950 p-4">
          <code className="text-white">{JSON.stringify(data, null, 2)}</code>
        </pre>
      ),
    })
  }

  return (
    <Form {...form}>
      <form onSubmit={form.handleSubmit(onSubmit)} className="space-y-6">
        <FormField
          control={form.control}
          name="language"
          render={({ field }) => (
            <FormItem className="flex flex-col">
              <FormLabel>Language</FormLabel>
              <Popover>
                <PopoverTrigger asChild>
                  <FormControl>
                    <Button
                      variant="outline"
                      role="combobox"
                      className={cn(
                        "w-[200px] justify-between",
                        !field.value && "text-muted-foreground"
                      )}
                    >
                      {field.value
                        ? languages.find(
                          (language) => language.value === field.value
                        )?.label
                        : "Select language"}
                      <ChevronsUpDown className="ml-2 h-4 w-4 shrink-0 opacity-50" />
                    </Button>
                  </FormControl>
                </PopoverTrigger>
                <PopoverContent className="w-[200px] p-0">
                  <Command>
                    <CommandInput placeholder="Search language..." />
+                   <CommandList>
                      <CommandEmpty>No language found.</CommandEmpty>
                      <CommandGroup>
                        {languages.map((language) => (
                          <CommandItem
                            value={language.label}
                            key={language.value}
                            onSelect={() => {
                              form.setValue("language", language.value)
                            }}
                          >
                            <Check
                              className={cn(
                                "mr-2 h-4 w-4",
                                language.value === field.value
                                  ? "opacity-100"
                                  : "opacity-0"
                              )}
                            />
                            {language.label}
                          </CommandItem>
                        ))}
                      </CommandGroup>
+                   </CommandList>
                  </Command>
                </PopoverContent>
              </Popover>
              <FormDescription>
                This is the language that will be used in the dashboard.
              </FormDescription>
              <FormMessage />
            </FormItem>
          )}
        />
        <Button type="submit">Submit</Button>
      </form>
    </Form>
  )
}