Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Multi select ? #66

Open
Flo-Slv opened this issue Feb 8, 2023 · 83 comments
Open

Multi select ? #66

Flo-Slv opened this issue Feb 8, 2023 · 83 comments

Comments

@Flo-Slv
Copy link

Flo-Slv commented Feb 8, 2023

Hi there ✋🏼

thanks for this amazing components !

Is there a way to select multiple data with the Select component ?

Thanks !

@shadcn
Copy link
Collaborator

shadcn commented Feb 8, 2023

Unfortunately no. The <Select /> element does not support multi-select. There's an issue on the Radix UI repo I'm following too: radix-ui/primitives#1342

@jackblackCH
Copy link

👍 Would love to have a Multi Select

@franciscohanna92
Copy link

@its-monotype Listbox from HeadlessUI (same creators as TailwindCSS) has support for multi-select

@99sdawkhar
Copy link

Hey @Flo-Slv, I also wanted a multi-select, one of my colleague suggested to use a dropdown-menu with checkboxes. It worked well for my use-case. Checked it out here.

@Flo-Slv
Copy link
Author

Flo-Slv commented Feb 20, 2023

Hey @Flo-Slv, I also wanted a multi-select, one of my colleague suggested to use a dropdown-menu with checkboxes. It worked well for my use-case. Checked it out here.

Hey ! It can be a workaround until they implement a native solution ! Thanks !

@hiql
Copy link

hiql commented Mar 24, 2023

https://github.com/colepeters/multiselect

What about this?

@evangow
Copy link

evangow commented Jun 2, 2023

I'd love see a multi-select with labels (instead of saying something like "4 items selected"), which is incredibly valuable for adding "tags" to things - a fairly common use case

Here's the one I'm currently using (not based on tailwind-css)
https://react.semantic-ui.com/modules/dropdown/

Here's a version using tailwind: https://demo-react-tailwindcss-select.vercel.app/
Github repo here: https://github.com/onesine/react-tailwindcss-select
^The downside to this one is that it doesn't look like it handles aria support / keyboard navigation

@oliviertassinari
Copy link

oliviertassinari commented Jun 6, 2023

There is a headless multi-select combobox in Base UI (import X from @mui/base/useAutocomplete) which is supposed to be feature-rich:

Screenshot 2023-06-06 at 14 19 53

https://mui.com/material-ui/react-autocomplete/#customized-hook

and small:

Screenshot 2023-06-06 at 14 17 34

https://bundlephobia.com/package/@mui/base@5.0.0-beta.4

maybe to consider as a base to style on top of, it could be a temporary solution for radix-ui/primitives#1342.

@evangow
Copy link

evangow commented Jun 12, 2023

In case anyone else comes to this issue looking for a solution, @mxkaske just dropped a mutli-select component built with cmdk and shadcn components.

Demo here: https://craft.mxkaske.dev/post/fancy-multi-select

Source here: https://github.com/mxkaske/mxkaske.dev/blob/main/components/craft/fancy-multi-select.tsx

@zachrip
Copy link

zachrip commented Jun 14, 2023

In case anyone else comes to this issue looking for a solution, @mxkaske just dropped a mutli-select component built with cmdk and shadcn components.

Demo here: https://craft.mxkaske.dev/post/fancy-multi-select

Source here: https://github.com/mxkaske/mxkaske.dev/blob/main/components/craft/fancy-multi-select.tsx

This isn't accessible

@evangow
Copy link

evangow commented Jun 14, 2023

@zachrip you can drop an issue in the repo here: https://github.com/mxkaske/mxkaske.dev/issues

@console-logs
Copy link

I tweaked Headless UI Listbox component to achieve the desired UI.

Here is the example code:

import { Listbox, Transition } from '@headlessui/react';
import { CaretSortIcon, CheckIcon } from '@radix-ui/react-icons';
import React from 'react';

export default function MultiSelect() {
	const [selected, setSelected] = React.useState(['None']);
	const [options, setOptions] = React.useState<string[]>([]);

	React.useEffect(() => {
		setOptions(['None', 'Apple', 'Orange', 'Banana', 'Grapes']);
	}, []);

	return (
		<Listbox
			value={selected}
			onChange={setSelected}
			multiple>
			<div className='relative'>
				<Listbox.Button className='flex h-9 w-full items-center justify-between rounded-md border border-input bg-transparent px-3 py-2 text-sm shadow-sm ring-offset-background placeholder:text-muted-foreground focus:outline-none focus:ring-1 focus:ring-ring disabled:cursor-not-allowed disabled:opacity-50'>
					<span className='block truncate'> {selected.map(option => option).join(', ')}</span>
					<CaretSortIcon className='h-4 w-4 opacity-50' />
				</Listbox.Button>
				<Transition
					as={React.Fragment}
					leave='transition ease-in duration-100'
					leaveFrom='opacity-100'
					leaveTo='opacity-0'>
					<Listbox.Options className='absolute z-50 mt-1 max-h-60 w-full overflow-auto rounded-md bg-popover py-1 text-base shadow-lg ring-1 ring-black ring-opacity-5 focus:outline-none sm:text-sm'>
						{options.map((option, optionIdx) => (
							<Listbox.Option
								key={optionIdx}
								className='relative cursor-default select-none py-1.5 pl-10 pr-4 text-sm rounded-sm outline-none focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50'
								value={option}>
								{({ selected }) => (
									<>
										{option}
										{selected ? (
											<span className='absolute inset-y-0 right-2 flex items-center pl-3'>
												<CheckIcon className='h-4 w-4' />
											</span>
										) : null}
									</>
								)}
							</Listbox.Option>
						))}
					</Listbox.Options>
				</Transition>
			</div>
		</Listbox>
	);
}

Hope this works for you.

Cheers!

@dinogit
Copy link

dinogit commented Sep 13, 2023

Hi all,

I have created component, I hope somebody will find it helpful:

import * as React from 'react'
import { cn } from "@/lib/utils"

import { Check, X, ChevronsUpDown } from "lucide-react"
import { Button } from "@/components/ui/button"
import {
    Command,
    CommandEmpty,
    CommandGroup,
    CommandInput,
    CommandItem,
} from "@/components/ui/command"
import {
    Popover,
    PopoverContent,
    PopoverTrigger,
} from "@/components/ui/popover"
import { Badge } from "@/components/ui/badge";


export type OptionType = {
    label: string;
    value: string;
}

interface MultiSelectProps {
    options: OptionType[];
    selected: string[];
    onChange: React.Dispatch<React.SetStateAction<string[]>>;
    className?: string;
}

function MultiSelect({ options, selected, onChange, className, ...props }: MultiSelectProps) {

    const [open, setOpen] = React.useState(false)

    const handleUnselect = (item: string) => {
        onChange(selected.filter((i) => i !== item))
    }

    return (
        <Popover open={open} onOpenChange={setOpen} {...props}>
            <PopoverTrigger asChild>
                <Button
                    variant="outline"
                    role="combobox"
                    aria-expanded={open}
                    className={`w-full justify-between ${selected.length > 1 ? "h-full" : "h-10"}`}
                    onClick={() => setOpen(!open)}
                >
                    <div className="flex gap-1 flex-wrap">
                        {selected.map((item) => (
                            <Badge
                                variant="secondary"
                                key={item}
                                className="mr-1 mb-1"
                                onClick={() => handleUnselect(item)}
                            >
                                {item}
                                <button
                                    className="ml-1 ring-offset-background rounded-full outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2"
                                    onKeyDown={(e) => {
                                        if (e.key === "Enter") {
                                            handleUnselect(item);
                                        }
                                    }}
                                    onMouseDown={(e) => {
                                        e.preventDefault();
                                        e.stopPropagation();
                                    }}
                                    onClick={() => handleUnselect(item)}
                                >
                                    <X className="h-3 w-3 text-muted-foreground hover:text-foreground" />
                                </button>
                            </Badge>
                        ))}
                    </div>
                    <ChevronsUpDown className="h-4 w-4 shrink-0 opacity-50" />
                </Button>
            </PopoverTrigger>
            <PopoverContent className="w-full p-0">
                <Command className={className}>
                    <CommandInput placeholder="Search ..." />
                    <CommandEmpty>No item found.</CommandEmpty>
                    <CommandGroup className='max-h-64 overflow-auto'>
                        {options.map((option) => (
                            <CommandItem
                                key={option.value}
                                onSelect={() => {
                                    onChange(
                                        selected.includes(option.value)
                                            ? selected.filter((item) => item !== option.value)
                                            : [...selected, option.value]
                                    )
                                    setOpen(true)
                                }}
                            >
                                <Check
                                    className={cn(
                                        "mr-2 h-4 w-4",
                                        selected.includes(option.value) ?
                                            "opacity-100" : "opacity-0"
                                    )}
                                />
                                {option.label}
                            </CommandItem>
                        ))}
                    </CommandGroup>
                </Command>
            </PopoverContent>
        </Popover>
    )
}

export { MultiSelect }

Use it like standalone component :

import * as React from 'react'
import { MultiSelect } from from "@/components/ui/multi-select"

function Demo() {
  const [selected, setSelected] = useState<string[]>([]);

  return (
    <MultiSelect
        options={[
          {
            value: "next.js",
            label: "Next.js",
          },
          {
            value: "sveltekit",
            label: "SvelteKit",
          },
          {
            value: "nuxt.js",
            label: "Nuxt.js",
          },
          {
            value: "remix",
            label: "Remix",
          },
          {
            value: "astro",
            label: "Astro",
          },
          {
            value: "wordpress",
            label: "WordPress",
          },
          {
            value: "express.js",
            label: "Express.js",
          },
        ]}
        selected={selected}
        onChange={setSelected}
        className="w-[560px]"
      />
  )
}

or part of React Hook Form:

<FormField
    control={form.control}
    name="industry"
    render={({ field }) => (
        <FormItem>
            <FormLabel>Select Frameworks</FormLabel>
                <MultiSelect
                    selected={field.value}
                    options={[
                    {
			            value: "next.js",
			            label: "Next.js",
			          },
			          {
			            value: "sveltekit",
			            label: "SvelteKit",
			          },
			          {
			            value: "nuxt.js",
			            label: "Nuxt.js",
			          },
			          {
			            value: "remix",
			            label: "Remix",
			          },
			          {
			            value: "astro",
			            label: "Astro",
			          },
			          {
			            value: "wordpress",
			            label: "WordPress",
			          },
			          {
			            value: "express.js",
			            label: "Express.js",
			          }
                    ]}
                    {...field}
                    className="sm:w-[510px]"
                />
            <FormMessage />
        </FormItem>
    )}
 />

@DarkAbhi
Copy link

Hi all,

I have created component, I hope somebody will find it helpful:

import * as React from 'react'
import { cn } from "@/lib/utils"

import { Check, X, ChevronsUpDown } from "lucide-react"
import { Button } from "@/components/ui/button"
import {
    Command,
    CommandEmpty,
    CommandGroup,
    CommandInput,
    CommandItem,
} from "@/components/ui/command"
import {
    Popover,
    PopoverContent,
    PopoverTrigger,
} from "@/components/ui/popover"
import { Badge } from "@/components/ui/badge";


export type OptionType = {
    label: string;
    value: string;
}

interface MultiSelectProps {
    options: OptionType[];
    selected: string[];
    onChange: React.Dispatch<React.SetStateAction<string[]>>;
    className?: string;
}

function MultiSelect({ options, selected, onChange, className, ...props }: MultiSelectProps) {

    const [open, setOpen] = React.useState(false)

    const handleUnselect = (item: string) => {
        onChange(selected.filter((i) => i !== item))
    }

    return (
        <Popover open={open} onOpenChange={setOpen} {...props}>
            <PopoverTrigger asChild>
                <Button
                    variant="outline"
                    role="combobox"
                    aria-expanded={open}
                    className={`w-full justify-between ${selected.length > 1 ? "h-full" : "h-10"}`}
                    onClick={() => setOpen(!open)}
                >
                    <div className="flex gap-1 flex-wrap">
                        {selected.map((item) => (
                            <Badge
                                variant="secondary"
                                key={item}
                                className="mr-1 mb-1"
                                onClick={() => handleUnselect(item)}
                            >
                                {item}
                                <button
                                    className="ml-1 ring-offset-background rounded-full outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2"
                                    onKeyDown={(e) => {
                                        if (e.key === "Enter") {
                                            handleUnselect(item);
                                        }
                                    }}
                                    onMouseDown={(e) => {
                                        e.preventDefault();
                                        e.stopPropagation();
                                    }}
                                    onClick={() => handleUnselect(item)}
                                >
                                    <X className="h-3 w-3 text-muted-foreground hover:text-foreground" />
                                </button>
                            </Badge>
                        ))}
                    </div>
                    <ChevronsUpDown className="h-4 w-4 shrink-0 opacity-50" />
                </Button>
            </PopoverTrigger>
            <PopoverContent className="w-full p-0">
                <Command className={className}>
                    <CommandInput placeholder="Search ..." />
                    <CommandEmpty>No item found.</CommandEmpty>
                    <CommandGroup className='max-h-64 overflow-auto'>
                        {options.map((option) => (
                            <CommandItem
                                key={option.value}
                                onSelect={() => {
                                    onChange(
                                        selected.includes(option.value)
                                            ? selected.filter((item) => item !== option.value)
                                            : [...selected, option.value]
                                    )
                                    setOpen(true)
                                }}
                            >
                                <Check
                                    className={cn(
                                        "mr-2 h-4 w-4",
                                        selected.includes(option.value) ?
                                            "opacity-100" : "opacity-0"
                                    )}
                                />
                                {option.label}
                            </CommandItem>
                        ))}
                    </CommandGroup>
                </Command>
            </PopoverContent>
        </Popover>
    )
}

export { MultiSelect }

Use it like standalone component :

import * as React from 'react'
import { MultiSelect } from from "@/components/ui/multi-select"

function Demo() {
  const [selected, setSelected] = useState<string[]>([]);

  return (
    <MultiSelect
        options={[
          {
            value: "next.js",
            label: "Next.js",
          },
          {
            value: "sveltekit",
            label: "SvelteKit",
          },
          {
            value: "nuxt.js",
            label: "Nuxt.js",
          },
          {
            value: "remix",
            label: "Remix",
          },
          {
            value: "astro",
            label: "Astro",
          },
          {
            value: "wordpress",
            label: "WordPress",
          },
          {
            value: "express.js",
            label: "Express.js",
          },
        ]}
        selected={selected}
        onChange={setSelected}
        className="w-[560px]"
      />
  )
}

or part of React Hook Form:

<FormField
    control={form.control}
    name="industry"
    render={({ field }) => (
        <FormItem>
            <FormLabel>Select Frameworks</FormLabel>
                <MultiSelect
                    selected={field.value}
                    options={[
                    {
			            value: "next.js",
			            label: "Next.js",
			          },
			          {
			            value: "sveltekit",
			            label: "SvelteKit",
			          },
			          {
			            value: "nuxt.js",
			            label: "Nuxt.js",
			          },
			          {
			            value: "remix",
			            label: "Remix",
			          },
			          {
			            value: "astro",
			            label: "Astro",
			          },
			          {
			            value: "wordpress",
			            label: "WordPress",
			          },
			          {
			            value: "express.js",
			            label: "Express.js",
			          }
                    ]}
                    {...field}
                    className="sm:w-[510px]"
                />
            <FormMessage />
        </FormItem>
    )}
 />

You can create a PR for this to be supported officially?

DarkAbhi added a commit to DarkAbhi/terrum-admin-panel that referenced this issue Sep 20, 2023
@zmzlois
Copy link

zmzlois commented Sep 21, 2023

Hi all,

I have created component, I hope somebody will find it helpful:

import * as React from 'react'
import { cn } from "@/lib/utils"

import { Check, X, ChevronsUpDown } from "lucide-react"
import { Button } from "@/components/ui/button"
import {
    Command,
    CommandEmpty,
    CommandGroup,
    CommandInput,
    CommandItem,
} from "@/components/ui/command"
import {
    Popover,
    PopoverContent,
    PopoverTrigger,
} from "@/components/ui/popover"
import { Badge } from "@/components/ui/badge";


export type OptionType = {
    label: string;
    value: string;
}

interface MultiSelectProps {
    options: OptionType[];
    selected: string[];
    onChange: React.Dispatch<React.SetStateAction<string[]>>;
    className?: string;
}

function MultiSelect({ options, selected, onChange, className, ...props }: MultiSelectProps) {

    const [open, setOpen] = React.useState(false)

    const handleUnselect = (item: string) => {
        onChange(selected.filter((i) => i !== item))
    }

    return (
        <Popover open={open} onOpenChange={setOpen} {...props}>
            <PopoverTrigger asChild>
                <Button
                    variant="outline"
                    role="combobox"
                    aria-expanded={open}
                    className={`w-full justify-between ${selected.length > 1 ? "h-full" : "h-10"}`}
                    onClick={() => setOpen(!open)}
                >
                    <div className="flex gap-1 flex-wrap">
                        {selected.map((item) => (
                            <Badge
                                variant="secondary"
                                key={item}
                                className="mr-1 mb-1"
                                onClick={() => handleUnselect(item)}
                            >
                                {item}
                                <button
                                    className="ml-1 ring-offset-background rounded-full outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2"
                                    onKeyDown={(e) => {
                                        if (e.key === "Enter") {
                                            handleUnselect(item);
                                        }
                                    }}
                                    onMouseDown={(e) => {
                                        e.preventDefault();
                                        e.stopPropagation();
                                    }}
                                    onClick={() => handleUnselect(item)}
                                >
                                    <X className="h-3 w-3 text-muted-foreground hover:text-foreground" />
                                </button>
                            </Badge>
                        ))}
                    </div>
                    <ChevronsUpDown className="h-4 w-4 shrink-0 opacity-50" />
                </Button>
            </PopoverTrigger>
            <PopoverContent className="w-full p-0">
                <Command className={className}>
                    <CommandInput placeholder="Search ..." />
                    <CommandEmpty>No item found.</CommandEmpty>
                    <CommandGroup className='max-h-64 overflow-auto'>
                        {options.map((option) => (
                            <CommandItem
                                key={option.value}
                                onSelect={() => {
                                    onChange(
                                        selected.includes(option.value)
                                            ? selected.filter((item) => item !== option.value)
                                            : [...selected, option.value]
                                    )
                                    setOpen(true)
                                }}
                            >
                                <Check
                                    className={cn(
                                        "mr-2 h-4 w-4",
                                        selected.includes(option.value) ?
                                            "opacity-100" : "opacity-0"
                                    )}
                                />
                                {option.label}
                            </CommandItem>
                        ))}
                    </CommandGroup>
                </Command>
            </PopoverContent>
        </Popover>
    )
}

export { MultiSelect }

Use it like standalone component :

import * as React from 'react'
import { MultiSelect } from from "@/components/ui/multi-select"

function Demo() {
  const [selected, setSelected] = useState<string[]>([]);

  return (
    <MultiSelect
        options={[
          {
            value: "next.js",
            label: "Next.js",
          },
          {
            value: "sveltekit",
            label: "SvelteKit",
          },
          {
            value: "nuxt.js",
            label: "Nuxt.js",
          },
          {
            value: "remix",
            label: "Remix",
          },
          {
            value: "astro",
            label: "Astro",
          },
          {
            value: "wordpress",
            label: "WordPress",
          },
          {
            value: "express.js",
            label: "Express.js",
          },
        ]}
        selected={selected}
        onChange={setSelected}
        className="w-[560px]"
      />
  )
}

or part of React Hook Form:

<FormField
    control={form.control}
    name="industry"
    render={({ field }) => (
        <FormItem>
            <FormLabel>Select Frameworks</FormLabel>
                <MultiSelect
                    selected={field.value}
                    options={[
                    {
			            value: "next.js",
			            label: "Next.js",
			          },
			          {
			            value: "sveltekit",
			            label: "SvelteKit",
			          },
			          {
			            value: "nuxt.js",
			            label: "Nuxt.js",
			          },
			          {
			            value: "remix",
			            label: "Remix",
			          },
			          {
			            value: "astro",
			            label: "Astro",
			          },
			          {
			            value: "wordpress",
			            label: "WordPress",
			          },
			          {
			            value: "express.js",
			            label: "Express.js",
			          }
                    ]}
                    {...field}
                    className="sm:w-[510px]"
                />
            <FormMessage />
        </FormItem>
    )}
 />

thank you, this is great. also wondering did anyone successfully make a form collect inputs correctly?

@Syammed2429
Copy link

Unfortunately no. The <Select /> element does not support multi-select. There's an issue on the Radix UI repo I'm following too: radix-ui/primitives#1342

Is there any component that has multi-select except the dropdown? @shadcn

@enesien
Copy link

enesien commented Oct 13, 2023

I created a multi input/select component but for tags that the user inputs rather than using a pre-defined list of options https://gist.github.com/enesien/03ba5340f628c6c812b306da5fedd1a4

@johnLamberts
Copy link

Hi all,

I have created component, I hope somebody will find it helpful:

import * as React from 'react'
import { cn } from "@/lib/utils"

import { Check, X, ChevronsUpDown } from "lucide-react"
import { Button } from "@/components/ui/button"
import {
    Command,
    CommandEmpty,
    CommandGroup,
    CommandInput,
    CommandItem,
} from "@/components/ui/command"
import {
    Popover,
    PopoverContent,
    PopoverTrigger,
} from "@/components/ui/popover"
import { Badge } from "@/components/ui/badge";


export type OptionType = {
    label: string;
    value: string;
}

interface MultiSelectProps {
    options: OptionType[];
    selected: string[];
    onChange: React.Dispatch<React.SetStateAction<string[]>>;
    className?: string;
}

function MultiSelect({ options, selected, onChange, className, ...props }: MultiSelectProps) {

    const [open, setOpen] = React.useState(false)

    const handleUnselect = (item: string) => {
        onChange(selected.filter((i) => i !== item))
    }

    return (
        <Popover open={open} onOpenChange={setOpen} {...props}>
            <PopoverTrigger asChild>
                <Button
                    variant="outline"
                    role="combobox"
                    aria-expanded={open}
                    className={`w-full justify-between ${selected.length > 1 ? "h-full" : "h-10"}`}
                    onClick={() => setOpen(!open)}
                >
                    <div className="flex gap-1 flex-wrap">
                        {selected.map((item) => (
                            <Badge
                                variant="secondary"
                                key={item}
                                className="mr-1 mb-1"
                                onClick={() => handleUnselect(item)}
                            >
                                {item}
                                <button
                                    className="ml-1 ring-offset-background rounded-full outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2"
                                    onKeyDown={(e) => {
                                        if (e.key === "Enter") {
                                            handleUnselect(item);
                                        }
                                    }}
                                    onMouseDown={(e) => {
                                        e.preventDefault();
                                        e.stopPropagation();
                                    }}
                                    onClick={() => handleUnselect(item)}
                                >
                                    <X className="h-3 w-3 text-muted-foreground hover:text-foreground" />
                                </button>
                            </Badge>
                        ))}
                    </div>
                    <ChevronsUpDown className="h-4 w-4 shrink-0 opacity-50" />
                </Button>
            </PopoverTrigger>
            <PopoverContent className="w-full p-0">
                <Command className={className}>
                    <CommandInput placeholder="Search ..." />
                    <CommandEmpty>No item found.</CommandEmpty>
                    <CommandGroup className='max-h-64 overflow-auto'>
                        {options.map((option) => (
                            <CommandItem
                                key={option.value}
                                onSelect={() => {
                                    onChange(
                                        selected.includes(option.value)
                                            ? selected.filter((item) => item !== option.value)
                                            : [...selected, option.value]
                                    )
                                    setOpen(true)
                                }}
                            >
                                <Check
                                    className={cn(
                                        "mr-2 h-4 w-4",
                                        selected.includes(option.value) ?
                                            "opacity-100" : "opacity-0"
                                    )}
                                />
                                {option.label}
                            </CommandItem>
                        ))}
                    </CommandGroup>
                </Command>
            </PopoverContent>
        </Popover>
    )
}

export { MultiSelect }

Use it like standalone component :

import * as React from 'react'
import { MultiSelect } from from "@/components/ui/multi-select"

function Demo() {
  const [selected, setSelected] = useState<string[]>([]);

  return (
    <MultiSelect
        options={[
          {
            value: "next.js",
            label: "Next.js",
          },
          {
            value: "sveltekit",
            label: "SvelteKit",
          },
          {
            value: "nuxt.js",
            label: "Nuxt.js",
          },
          {
            value: "remix",
            label: "Remix",
          },
          {
            value: "astro",
            label: "Astro",
          },
          {
            value: "wordpress",
            label: "WordPress",
          },
          {
            value: "express.js",
            label: "Express.js",
          },
        ]}
        selected={selected}
        onChange={setSelected}
        className="w-[560px]"
      />
  )
}

or part of React Hook Form:

<FormField
    control={form.control}
    name="industry"
    render={({ field }) => (
        <FormItem>
            <FormLabel>Select Frameworks</FormLabel>
                <MultiSelect
                    selected={field.value}
                    options={[
                    {
			            value: "next.js",
			            label: "Next.js",
			          },
			          {
			            value: "sveltekit",
			            label: "SvelteKit",
			          },
			          {
			            value: "nuxt.js",
			            label: "Nuxt.js",
			          },
			          {
			            value: "remix",
			            label: "Remix",
			          },
			          {
			            value: "astro",
			            label: "Astro",
			          },
			          {
			            value: "wordpress",
			            label: "WordPress",
			          },
			          {
			            value: "express.js",
			            label: "Express.js",
			          }
                    ]}
                    {...field}
                    className="sm:w-[510px]"
                />
            <FormMessage />
        </FormItem>
    )}
 />

I am getting an error through the selected item, I am using react hook form

<FormField control={form.control} name="authors" render={({ field: { ...field } }) => ( <FormItem className="mb-5"> <FormLabel>Author</FormLabel> <MultiSelect selected={field.value} options={authorsData} {...field} /> </FormItem> )} />
it says that, selected is not iterable, I already check the onSelect method from CommandItem but I can't find any solution

@dinogit
Copy link

dinogit commented Oct 23, 2023

@johnLamberts PR is still in progress, so until this is done, copy code from here, fix some imports and let me know does it work.

@johnLamberts
Copy link

johnLamberts commented Oct 23, 2023

@johnLamberts PR is still in progress, so until this is done, copy code from here, fix some imports and let me know does it work.

I am still getting the same error, I have already check the code.

import * as React from "react";
import { Badge } from "@/shared/components/ui/badge";
import { Button } from "@/shared/components/ui/button";
import {
  Command,
  CommandEmpty,
  CommandGroup,
  CommandInput,
  CommandItem,
} from "@/shared/components/ui/command";
import {
  Popover,
  PopoverContent,
  PopoverTrigger,
} from "@/shared/components/ui/popover";
import { cn } from "@/shared/lib/utils";
import { Check, ChevronsUpDown, X } from "lucide-react";
import { useState } from "react";

// export type OptionType = {
//   id: string;
//   value: string;
// };

export type OptionType = Record<"id" | "value", string>;

interface MultiSelectProps {
  options: Record<"id" | "value", string>[];
  selected: Record<"id" | "value", string>[];
  onChange: React.Dispatch<
    React.SetStateAction<Record<"id" | "value", string>[]>
  >;
  className?: string;
}

const MultiSelect = React.forwardRef<HTMLButtonElement, MultiSelectProps>(
  ({ options, selected, onChange, className, ...props }, ref) => {
    const [open, setOpen] = useState(false);

    const handleUnselect = (item: Record<"id" | "value", string>) => {
      onChange(selected.filter((i) => i.id !== item.id));
    };

    return (
      <Popover open={open} onOpenChange={setOpen} {...props}>
        <PopoverTrigger asChild>
          <Button
            ref={ref}
            role="combobox"
            variant="outline"
            aria-expanded={open}
            className={`w-full justify-between  ${
              selected?.length > 1 ? "h-full" : "h-10"
            }`}
            onClick={() => setOpen(!open)}
          >
            <div className="flex gap-1 flex-wrap">
              {selected?.map((item) => (
                <Badge
                  variant="secondary"
                  key={item.id}
                  className="mr-1 mb-1"
                  onClick={() => handleUnselect(item)}
                >
                  {item.value}
                  <button
                    className="ml-1 ring-offset-background rounded-full outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2"
                    onKeyDown={(e) => {
                      if (e.key === "Enter") {
                        handleUnselect(item);
                      }
                    }}
                    onMouseDown={(e) => {
                      e.preventDefault();
                      e.stopPropagation();
                    }}
                    onClick={() => handleUnselect(item)}
                  >
                    <X className="h-3 w-3 text-muted-foreground hover:text-foreground" />
                  </button>
                </Badge>
              ))}
            </div>
            <ChevronsUpDown className="h-4 w-4 shrink-0 opacity-50" />
          </Button>
        </PopoverTrigger>
        <PopoverContent className="">
          <Command className={className}>
            <CommandInput placeholder="Search..." />
            <CommandEmpty>No item found.</CommandEmpty>
            <CommandGroup className="h-32 overflow-auto">
              {options.map((option) => (
                <CommandItem
                  key={option.id}
                  onSelect={() => {
                    console.log(option.value);
                    console.log(selected);
                    onChange(
                      selected?.some(
                        (item: Record<"id" | "value", string>) =>
                          item.id === option.id
                      )
                        ? selected.filter((item) => item.id !== option.id)
                        : [...selected, option]
                    );
                    setOpen(true);
                  }}
                >
                  <Check
                    className={cn(
                      "mr-2 h-4 w-4",
                      selected?.some((item) => item.id === option.id)
                        ? "opacity-100"
                        : "opacity-0"
                    )}
                  />
                  {option.value}
                </CommandItem>
              ))}
            </CommandGroup>
          </Command>
        </PopoverContent>
      </Popover>
    );
  }
);

MultiSelect.displayName = "MultiSelect";
export { MultiSelect };
``


`

btw, it the `selected` always returned me undefined, and I already check my forms well

@dinogit
Copy link

dinogit commented Oct 23, 2023

import { z } from "zod";
import { useForm } from "react-hook-form";
import { zodResolver } from "@hookform/resolvers/zod";

import {
  Form,
  FormField,
  FormItem,
  FormLabel,
  FormMessage,
} from "@/components/ui/form";
import { MultiSelect } from "@/components/ui/multi-select"
const AuthorsSchema = z.array(
    z.record(
        z.string().trim()
    )
)
const form = useForm<z.infer<typeof AuthorsSchema>>({
    resolver: zodResolver(AuthorsSchema),
    defaultValues: {
      authors: [],
    },
  });
const onHandleSubmit = (values: z.infer<typeof AuthorsSchema>) => {
    console.log({ values })
  };

const authorsData = [
    {
      value: "author1",
      label: "Author 1",
    }, {
      value: "author2",
      label: "Author 2",
    },
    {
      value: "author3",
      label: "Author 3",
    },
    {
      value: "author4",
      label: "Author 4",
    }
  ]
<Form {...form}>
              <form
                onSubmit={form.handleSubmit(onHandleSubmit)}
                className="space-y-4"
              >
                <FormField
                  control={form.control}
                  name="authors"
                  render={({ field: { ...field } }) => (
                    <FormItem className="mb-5">
                      <FormLabel>Author</FormLabel>
                      <MultiSelect
                        selected={field.value}
                        options={authorsData}
                        {...field} />
                    </FormItem>
                  )}
                />
                <Button type="submit" className="w-full">
                  Continue
                </Button>
              </form>
            </Form>

@Ryanv030
Copy link

In case anyone else comes to this issue looking for a solution, @mxkaske just dropped a mutli-select component built with cmdk and shadcn components.

Demo here: https://craft.mxkaske.dev/post/fancy-multi-select

Source here: https://github.com/mxkaske/mxkaske.dev/blob/main/components/craft/fancy-multi-select.tsx

Unfortunately this isn't screen reader accessible. Once the dropdown opens the screen reader's focus stays on the initial button that opens the dropdown.

@gallirohik
Copy link

gallirohik commented Mar 19, 2024

This code works like a charm. thanks @dinogit
Expanding this logic, added action button to add custom option. Hope this helps.

import * as React from "react";
import { cn } from "@/lib/utils";

import { Check, X, ChevronsUpDown, PlusCircleIcon } from "lucide-react";
import { Button } from "@/components/ui/button";
import {
  Command,
  CommandEmpty,
  CommandGroup,
  CommandInput,
  CommandItem,
  CommandSeparator,
} from "@/components/ui/command";
import {
  Popover,
  PopoverContent,
  PopoverTrigger,
} from "@/components/ui/popover";
import { Badge } from "@/components/ui/badge";
import { Input } from "../ui/input";

export type OptionType = {
  label: string;
  value: string;
};

interface MultiSelectProps {
  options: OptionType[];
  selected: string[];
  onChange: React.Dispatch<React.SetStateAction<string[]>>;
  className?: string;
}

function MultiSelect({
  options,
  selected,
  onChange,
  className,
  ...props
}: MultiSelectProps) {
  const [open, setOpen] = React.useState(false);

  const handleUnselect = (item: string) => {
    onChange(selected.filter((i) => i !== item));
  };

  const [newOption, setNewOption] = React.useState("");

  const handleNewOptionEntry = (e: React.ChangeEvent<HTMLInputElement>) => {
    setNewOption(e.target.value);
  };

  const handleNewOptionSubmit = () => {
    if (newOption) {
      options.push({ label: newOption, value: newOption });
      onChange(
        selected.includes(newOption)
          ? selected.filter((item) => item !== newOption)
          : [...selected, newOption]
      );
      setNewOption("");
      setOpen(true);
    }
  };

  return (
    <Popover open={open} onOpenChange={setOpen} {...props}>
      <PopoverTrigger asChild>
        <Button
          variant="outline"
          role="combobox"
          aria-expanded={open}
          className={`w-full justify-between ${
            selected.length > 1 ? "h-full" : "h-10"
          }`}
          onClick={() => setOpen(!open)}
        >
          <div className="flex gap-1 flex-wrap">
            {selected.map((item) => (
              <Badge
                variant="secondary"
                key={item}
                className="mr-1 mb-1"
                onClick={() => handleUnselect(item)}
              >
                {item}
                <button
                  className="ml-1 ring-offset-background rounded-full outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2"
                  onKeyDown={(e) => {
                    if (e.key === "Enter") {
                      handleUnselect(item);
                    }
                  }}
                  onMouseDown={(e) => {
                    e.preventDefault();
                    e.stopPropagation();
                  }}
                  onClick={() => handleUnselect(item)}
                >
                  <X className="h-3 w-3 text-muted-foreground hover:text-foreground" />
                </button>
              </Badge>
            ))}
          </div>
          <ChevronsUpDown className="h-4 w-4 shrink-0 opacity-50" />
        </Button>
      </PopoverTrigger>
      <PopoverContent className="w-full p-0">
        <Command className={className}>
          <CommandInput placeholder="Search ..." />
          <CommandEmpty>No item found.</CommandEmpty>
          <CommandGroup className="max-h-64 overflow-auto">
            {options.map((option) => (
              <CommandItem
                key={option.value}
                onSelect={() => {
                  onChange(
                    selected.includes(option.value)
                      ? selected.filter((item) => item !== option.value)
                      : [...selected, option.value]
                  );
                  setOpen(true);
                }}
              >
                <Check
                  className={cn(
                    "mr-2 h-4 w-4",
                    selected.includes(option.value)
                      ? "opacity-100"
                      : "opacity-0"
                  )}
                />
                {option.label}
              </CommandItem>
            ))}
          </CommandGroup>
          <CommandSeparator />
          <CommandGroup>
            <div className="flex gap-1">
              <Input
                placeholder="other tags"
                value={newOption}
                onChange={handleNewOptionEntry}
              />
              <Button variant="ghost" onClick={handleNewOptionSubmit}>
                <PlusCircleIcon />
              </Button>
            </div>
          </CommandGroup>
        </Command>
      </PopoverContent>
    </Popover>
  );
}

export { MultiSelect };

@stephengade
Copy link

stephengade commented Mar 21, 2024

onClick is not working. when an item is clicked, it is supposed to select it or unselect but currently not working.

EDIT: It's working now after changing the disable pseudo in CommandItem component.

change data-[disabled] to data-[disabled='true']

 "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",

@supern64
Copy link

supern64 commented Apr 9, 2024

I've ported dinogit's component into the Vue version of shadcn in case someone happens to come across this thread. It's not perfect but it works!

<script setup lang="ts">
import { computed, ref, useAttrs } from 'vue';
import { cn } from '@/lib/utils';

import { Check, X, ChevronsUpDown } from "lucide-vue-next"
import { Button } from "@/components/ui/button"
import {
    Command,
    CommandEmpty,
    CommandGroup,
    CommandInput,
    CommandItem,
    CommandList
} from "@/components/common/ui/command"
import {
    Popover,
    PopoverContent,
    PopoverTrigger,
} from "@/components/ui/popover"
import { Badge } from "@/components/ui/badge"; 
import { ScrollArea } from '@/components/ui/scroll-area';

export type OptionType = {
    label: string;
    value: string;
}

defineOptions({
    inheritAttrs: false
})

defineProps<{
    options: OptionType[]
}>();

const selected = defineModel<OptionType[]>({ default: [] });
const open = ref(false);
const attrs = useAttrs();

const buttonClass = computed(() => cn(
    "w-full justify-between",
    { "h-full": selected.length > 1, "h-10": selected.length <= 1 }
));

function toggleOpen() {
    open.value = !open.value;
}

function unselect(item: string) {
    selected.value = selected.value.filter((i) => i.value !== item);
}
</script>

<template>
    <Popover :open="open">
        <PopoverTrigger as-child>
            <Button
                variant="outline"
                role="combobox"
                :aria-expanded="open"
                :class="buttonClass"
                @click="toggleOpen()"
            >
                <div class="flex gap-1 flex-wrap">
                    <Badge
                        variant="secondary"
                        v-for="item in selected"
                        :key="item.value"
                        class="mr-1 mb-1"
                        @click="unselect(item.value)"
                    >
                        {{ item.label }}
                        <button
                            class="ml-1 ring-offset-background rounded-full outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2"
                            @keydown="(e) => { if (e.key === 'Enter') unselect(item.value) }"
                            @mousedown.stop.prevent
                            @click="unselect(item.value)"
                        >
                            <X class="h-3 w-3 text-muted-foreground hover:text-foreground" />
                        </button>
                    </Badge>
                </div>
                <ChevronsUpDown class="h-4 w-4 shrink-0 opacity-50" />
            </Button>
        </PopoverTrigger>
        <PopoverContent class="w-full p-0">
            <Command :class="cn('flex h-full w-full flex-col overflow-hidden rounded-md bg-popover text-popover-foreground', attrs.class as string)">
                <CommandInput placeholder="Search..." />
                <CommandList>
                    <ScrollArea class="h-36 p-1">
                        <CommandEmpty>No items found.</CommandEmpty>
                        <CommandGroup>
                                <CommandItem
                                    v-for="option in options"
                                    :key="option.value"
                                    :value="option.label"
                                    class="hover:cursor-pointer"
                                    @select="() => {
                                        if (selected.map((r) => r.value).includes(option.value)) {
                                            unselect(option.value);
                                        } else {
                                            selected = [...selected, option];
                                        }
                                        open = true;
                                    }"
                                >
                                    <Check
                                        v-if="selected.map((r) => r.value).includes(option.value)"
                                        :class="cn('mr-2 h-4 w-4', { 'opacity-100': selected.map((r) => r.value).includes(option.value), 'opacity-0': !selected.map((r) => r.value).includes(option.value)})"
                                    />
                                    {{ option.label }}
                                </CommandItem>
                        </CommandGroup>
                    </ScrollArea>
                </CommandList>
            </Command>
        </PopoverContent>
    </Popover>
</template>

@villszer
Copy link

Hi all,

I have created component, I hope somebody will find it helpful:

I got an error.

Warning: validateDOMNesting(...): <button> cannot appear as a descendant of <button>.
    at button
    at div
    at Badge (http://localhost:5173/src/components/ui/badge.tsx:35:18)
    at div
    at button
    at _c (http://localhost:5173/src/components/ui/button.tsx:47:11)

@sersavan
Copy link

I've assembled a multi-select component using the native shadcn's components. It's fully in line with design and integrates seamlessly into shadcn's ecosystem. Please, try it out and share your thoughts.
https://shadcn-multi-select-component.vercel.app/

Screenshot 2024-04-11 at 00 50 06

@timwehrle
Copy link

I've assembled a multi-select component using the native shadcn's components. It's fully in line with design and integrates seamlessly into shadcn's ecosystem. Please, try it out and share your thoughts. https://shadcn-multi-select-component.vercel.app/
Screenshot 2024-04-11 at 00 50 06

Hey, yes, that looks good! The previous error was resolved by using divs as buttons, although this approach lacks semantic value. However, it works. Can we improve keyboard accessibility? I couldn't navigate through the component using my keyboard.

@sersavan
Copy link

I've assembled a multi-select component using the native shadcn's components. It's fully in line with design and integrates seamlessly into shadcn's ecosystem. Please, try it out and share your thoughts. https://shadcn-multi-select-component.vercel.app/

Hey, yes, that looks good! The previous error was resolved by using divs as buttons, although this approach lacks semantic value. However, it works. Can we improve keyboard accessibility? I couldn't navigate through the component using my keyboard.

OK, I’ll finalize the component for full interaction with the keyboard.

@hitecSmartHome
Copy link

I've assembled a multi-select component using the native shadcn's components. It's fully in line with design and integrates seamlessly into shadcn's ecosystem. Please, try it out and share your thoughts.
https://shadcn-multi-select-component.vercel.app/

Screenshot 2024-04-11 at 00 50 06

Neat! Will try it

@sersavan
Copy link

sersavan commented Apr 12, 2024

I've assembled a multi-select component using the native shadcn's components. It's fully in line with design and integrates seamlessly into shadcn's ecosystem. Please, try it out and share your thoughts. https://shadcn-multi-select-component.vercel.app/

Hey, yes, that looks good! The previous error was resolved by using divs as buttons, although this approach lacks semantic value. However, it works. Can we improve keyboard accessibility? I couldn't navigate through the component using my keyboard.

to @timwehrle

Hi,
I've finished updating the components to include keyboard support. I've added a handler for some keys:

  • [Enter] for opening a menu and selecting values
  • [Esc] for closing a menu
  • [Backspace] for deleting elements

Try it here: https://shadcn-multi-select-component.vercel.app/

@snufkind
Copy link

@sersavan I can't get your component to work. Options are disabled for some reason for me even though I have identical multi-select component as yours 🤔

@sersavan
Copy link

sersavan commented Apr 13, 2024

@sersavan I can't get your component to work. Options are disabled for some reason for me even though I have identical multi-select component as yours 🤔

to @snufkind

check "cmdk" version - it should be 0.2.0

image

@sersavan
Copy link

sersavan commented Apr 13, 2024

to @snufkind

I've fixed issue with cmdk, now you can use latest version as well

@joaopedrodcf
Copy link

Really awesome work with this component @sersavan !

I was looking into the aria-selected of each of the CommandItems and seems they are not following what's really selected, as we are controlling in the component the state of each item ourselves.

image

Did you also noticed that ?

@sersavan
Copy link

@joaopedrodcf
It came from cmdk, but in my opinion this "area-select" property doesn't matter much for case of multi-select element as form element
Here mdn's reference (default tor tab):
image

@cbptamtom
Copy link

I've assembled a multi-select component using the native shadcn's components. It's fully in line with design and integrates seamlessly into shadcn's ecosystem. Please, try it out and share your thoughts. https://shadcn-multi-select-component.vercel.app/

Screenshot 2024-04-11 at 00 50 06

Thanks @sersavan. I really like the UI, but I'd prefer to use it with numerical values. Could you assist me with that?

@sersavan
Copy link

I've assembled a multi-select component using the native shadcn's components. It's fully in line with design and integrates seamlessly into shadcn's ecosystem. Please, try it out and share your thoughts. https://shadcn-multi-select-component.vercel.app/
Screenshot 2024-04-11 at 00 50 06

Thanks @sersavan. I really like the UI, but I'd prefer to use it with numerical values. Could you assist me with that?

@cbptamtom
give me an example

@cbptamtom
Copy link

cbptamtom commented Apr 13, 2024

I've assembled a multi-select component using the native shadcn's components. It's fully in line with design and integrates seamlessly into shadcn's ecosystem. Please, try it out and share your thoughts. https://shadcn-multi-select-component.vercel.app/
Screenshot 2024-04-11 at 00 50 06

Thanks @sersavan. I really like the UI, but I'd prefer to use it with numerical values. Could you assist me with that?

@cbptamtom give me an example
Hi @sersavan
I using the type
image

and in my form. I just use warehouse_id is a number array [number]
image

This's the issue in my UI.
image

@sersavan
Copy link

@cbptamtom
this component returns an string[]
so, you can parse it or use z.coerce

@cbptamtom
Copy link

@cbptamtom this component returns an string[] so, you can parse it or use z.coerce

Thanks @sersavan. I've fixed

@snufkind
Copy link

@sersavan You're doing god's work here 😅

Only thing that would make this absolutely perfect is replacing the breadcrumb's with a text. For example "6 options selected" so that the element doesn't overflow or grow horizontally.

@sersavan
Copy link

sersavan commented Apr 13, 2024

@sersavan You're doing god's work here 😅

Only thing that would make this absolutely perfect is replacing the breadcrumb's with a text. For example "6 options selected" so that the element doesn't overflow or grow horizontally.

@snufkind
badges - that's the whole point for me))
I'll look for a way to give the user their choice

@Tony-Stark-Jr
Copy link

@sersavan First thanks. I am unable to add my own style to the component. Can you help me to address this issue.

@sersavan
Copy link

sersavan commented Apr 14, 2024

@sersavan First thanks. I am unable to add my own style to the component. Can you help me to address this issue.

Hi, I've added a few props, including className and variant, as in the native shadcn/ui.
Now you can control the style of the component yourself.
Preset variants: default, secondary, destructive, inverted.
The animation is enabled by adding a prop animation in which you set the animation speed (less -> faster), along with it a magic wand appears so that the user can always turn it off.

image

@zekageri
Copy link

@sersavan First thanks. I am unable to add my own style to the component. Can you help me to address this issue.

Hi, I've added a few props, including className and variant, as in the native shadcn/ui. Now you can control the style of the component yourself. Preset variants: default, secondary, destructive, inverted. The animation is enabled by adding a prop animation in which you set the animation speed (less -> faster), along with it a magic wand appears so that the user can always turn it off.

image

Where does it updated?

@sersavan
Copy link

Where does it updated?

@zekageri
If I understood your question correctly, then you can use this props in the place where you add this component, for example, on the page (like in my repo)

@SwiichyCode
Copy link

SwiichyCode commented Apr 29, 2024

Hello any accessible solution for app-index.js:33 Warning: In HTML, button cannot be a descendant of button.

@AhmedBelkadi
Copy link

<FormField
    control={form.control}
    name="industry"
    render={({ field }) => (
        <FormItem>
            <FormLabel>Select Frameworks</FormLabel>
                <MultiSelect
                    selected={field.value}
                    options={[
                    {
			            value: "next.js",
			            label: "Next.js",
			          },
			          {
			            value: "sveltekit",
			            label: "SvelteKit",
			          },
			          {
			            value: "nuxt.js",
			            label: "Nuxt.js",
			          },
			          {
			            value: "remix",
			            label: "Remix",
			          },
			          {
			            value: "astro",
			            label: "Astro",
			          },
			          {
			            value: "wordpress",
			            label: "WordPress",
			          },
			          {
			            value: "express.js",
			            label: "Express.js",
			          }
                    ]}
                    {...field}
                    className="sm:w-[510px]"
                />
            <FormMessage />
        </FormItem>
    )}
 />

not working !!

Unexpected Application Error!
Cannot read properties of undefined (reading 'length')
TypeError: Cannot read properties of undefined (reading 'length')
at MultiSelect (http://localhost:5173/src/components/ui/MultiSelect.tsx:48:55)
at renderWithHooks (http://localhost:5173/node_modules/.vite/deps/chunk-B27YY5WJ.js?v=0e6ec46c:11568:26)
at mountIndeterminateComponent (http://localhost:5173/node_modules/.vite/deps/chunk-B27YY5WJ.js?v=0e6ec46c:14946:21)
at beginWork (http://localhost:5173/node_modules/.vite/deps/chunk-B27YY5WJ.js?v=0e6ec46c:15934:22)
at beginWork$1 (http://localhost:5173/node_modules/.vite/deps/chunk-B27YY5WJ.js?v=0e6ec46c:19781:22)
at performUnitOfWork (http://localhost:5173/node_modules/.vite/deps/chunk-B27YY5WJ.js?v=0e6ec46c:19226:20)
at workLoopSync (http://localhost:5173/node_modules/.vite/deps/chunk-B27YY5WJ.js?v=0e6ec46c:19165:13)
at renderRootSync (http://localhost:5173/node_modules/.vite/deps/chunk-B27YY5WJ.js?v=0e6ec46c:19144:15)
at recoverFromConcurrentError (http://localhost:5173/node_modules/.vite/deps/chunk-B27YY5WJ.js?v=0e6ec46c:18764:28)
at performConcurrentWorkOnRoot (http://localhost:5173/node_modules/.vite/deps/chunk-B27YY5WJ.js?v=0e6ec46c:18712:30)

@sersavan
Copy link

@AhmedBelkadi
Your question is related to what solution?
If with mine repo, then there is a different implementation including other props

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests