Multi-select
formcn/multi-selectFreeComponent
Multi-select dropdown
Install it
npx shadcn@latest add https://formcn.dev/r/multi-select.jsonSource
1'use client'23import { CheckIcon, ChevronsUpDownIcon, XIcon } from 'lucide-react'4import {5 type ComponentPropsWithoutRef,6 createContext,7 type ReactNode,8 useCallback,9 useContext,10 useEffect,11 useRef,12 useState,13} from 'react'14import { Badge } from '@/components/ui/badge'15import { Button } from '@/components/ui/button'16import {17 Command,18 CommandEmpty,19 CommandGroup,20 CommandInput,21 CommandItem,22 CommandList,23 CommandSeparator,24} from '@/components/ui/command'25import {26 Popover,27 PopoverContent,28 PopoverTrigger,29} from '@/components/ui/popover'30import { cn } from '@/lib/utils'3132type MultiSelectContextType = {33 open: boolean34 setOpen: (open: boolean) => void35 selectedValues: Set<string>36 toggleValue: (value: string) => void37 items: Map<string, ReactNode>38 onItemAdded: (value: string, label: ReactNode) => void39}40const MultiSelectContext = createContext<MultiSelectContextType | null>(null)4142export function MultiSelect({43 children,44 values,45 defaultValues,46 onValuesChange,47}: {48 children: ReactNode49 values?: string[]50 defaultValues?: string[]51 onValuesChange?: (values: string[]) => void52}) {53 const [open, setOpen] = useState(false)54 const [internalValues, setInternalValues] = useState(55 new Set<string>(values ?? defaultValues),56 )57 const selectedValues = values ? new Set(values) : internalValues58 const [items, setItems] = useState<Map<string, ReactNode>>(new Map())5960 function toggleValue(value: string) {61 const getNewSet = (prev: Set<string>) => {62 const newSet = new Set(prev)63 if (newSet.has(value)) {64 newSet.delete(value)65 } else {66 newSet.add(value)67 }68 return newSet69 }70 setInternalValues(getNewSet)71 onValuesChange?.([...getNewSet(selectedValues)])72 }7374 const onItemAdded = useCallback((value: string, label: ReactNode) => {75 setItems((prev) => {76 if (prev.get(value) === label) return prev77 return new Map(prev).set(value, label)78 })79 }, [])8081 return (82 <MultiSelectContext83 value={{84 open,85 setOpen,86 selectedValues,87 toggleValue,88 items,89 onItemAdded,90 }}91 >92 <Popover open={open} onOpenChange={setOpen} modal={true}>93 {children}94 </Popover>95 </MultiSelectContext>96 )97}9899export function MultiSelectTrigger({100 className,101 children,102 ...props103}: {104 className?: string105 children?: ReactNode106} & ComponentPropsWithoutRef<typeof Button>) {107 const { open } = useMultiSelectContext()108109 return (110 <PopoverTrigger asChild>111 <Button112 {...props}113 variant={props.variant ?? 'outline'}114// … truncated
What it pulls in
Other registry items
Files it writes
More from formcn
All 9 items| Component | Registry | Kind | Access | Installs | Command |
|---|---|---|---|---|---|
| File Inputfile-upload | formcn | Components | Free | no deps | |
| Multi-step formmulti-step-viewer | formcn | Components | Free | 1 dep | |
| Passwordpassword | formcn | Components | Free | no deps | |
| Ratingrating | formcn | Components | Free | no deps | |
| Stepperstepper | formcn | Components | Free | no deps | |
| Tag Inputtag-input | formcn | Components | Free | 1 dep |
