-
-
Save sayandedotcom/cfd39848edd55a2955b2a5efea99dc8e to your computer and use it in GitHub Desktop.
| 1. Select Component --------------------------------------------------------------------------------- | |
| "use client"; | |
| import clsx from "clsx"; | |
| import { ChevronDownIcon, X } from "lucide-react"; | |
| import Select, { | |
| ClearIndicatorProps, | |
| DropdownIndicatorProps, | |
| MultiValueRemoveProps, | |
| components, | |
| } from "react-select"; | |
| import makeAnimated from "react-select/animated"; | |
| import CreatableSelect from "react-select/creatable"; | |
| const DropdownIndicator = (props: DropdownIndicatorProps) => { | |
| return ( | |
| <components.DropdownIndicator {...props}> | |
| <ChevronDownIcon /> | |
| </components.DropdownIndicator> | |
| ); | |
| }; | |
| const ClearIndicator = (props: ClearIndicatorProps) => { | |
| return ( | |
| <components.ClearIndicator {...props}> | |
| <X /> | |
| </components.ClearIndicator> | |
| ); | |
| }; | |
| const MultiValueRemove = (props: MultiValueRemoveProps) => { | |
| return ( | |
| <components.MultiValueRemove {...props}> | |
| <X /> | |
| </components.MultiValueRemove> | |
| ); | |
| }; | |
| const controlStyles = { | |
| base: "border border-border rounded-lg bg-background hover:cursor-pointer hover:bg-secondary", | |
| focus: "border-border ring-ring ring-primary-500", | |
| nonFocus: "border-border", | |
| }; | |
| const placeholderStyles = "text-muted-foreground text-sm ml-1"; | |
| const selectInputStyles = "text-foreground text-sm ml-1"; | |
| const valueContainerStyles = "text-foreground text-sm"; | |
| const singleValueStyles = "ml-1"; | |
| const multiValueStyles = | |
| "ml-1 bg-background border border-border rounded items-center py-0.5 pl-2 pr-1 gap-1.5"; | |
| const multiValueLabelStyles = "leading-6 py-0.5"; | |
| const multiValueRemoveStyles = | |
| "border border-gray-200 bg-white hover:bg-red-50 hover:text-red-800 text-gray-500 hover:border-red-300 rounded-md bg-background"; | |
| const indicatorsContainerStyles = "p-1 gap-1 bg-background rounded-lg"; | |
| const clearIndicatorStyles = "text-gray-500 p-1 rounded-md hover:text-red-800"; | |
| const indicatorSeparatorStyles = "bg-mutated"; | |
| const dropdownIndicatorStyles = "p-1 hover:text-foreground text-gray-500"; | |
| const menuStyles = "mt-2 p-2 border border-border bg-background text-sm rounded-lg"; | |
| const optionsStyle = "bg-background p-2 border-0 text-base hover:bg-secondary hover:cursor-pointer"; | |
| const groupHeadingStyles = "ml-3 mt-2 mb-1 text-gray-500 text-sm bg-background"; | |
| const noOptionsMessageStyles = "text-muted-foreground bg-background"; | |
| type SelectComponentProps = { | |
| options: any[]; | |
| value?: any; | |
| onChange?: (value: any) => void; | |
| isMulti?: boolean; | |
| isDisabled?: boolean; | |
| isLoading?: boolean; | |
| createAble: boolean; | |
| placeholder?: string; | |
| }; | |
| export const SelectComponent = ({ | |
| options, | |
| value, | |
| onChange, | |
| isMulti, | |
| isDisabled, | |
| isLoading, | |
| createAble, | |
| placeholder, | |
| ...props | |
| }: SelectComponentProps) => { | |
| const animatedComponents = makeAnimated(); | |
| const Comp = createAble ? CreatableSelect : Select; | |
| return ( | |
| <> | |
| <Comp | |
| unstyled | |
| isClearable | |
| isSearchable | |
| value={value} | |
| isDisabled={isDisabled} | |
| isMulti={isMulti} | |
| isLoading={isLoading} | |
| placeholder={placeholder} | |
| components={animatedComponents} | |
| // defaultInputValue={defaultValue} | |
| defaultValue={value} | |
| options={options} | |
| noOptionsMessage={() => "No options found !!"} | |
| onChange={onChange} | |
| classNames={{ | |
| control: ({ isFocused }) => | |
| clsx(isFocused ? controlStyles.focus : controlStyles.nonFocus, controlStyles.base), | |
| placeholder: () => placeholderStyles, | |
| input: () => selectInputStyles, | |
| option: () => optionsStyle, | |
| menu: () => menuStyles, | |
| valueContainer: () => valueContainerStyles, | |
| singleValue: () => singleValueStyles, | |
| multiValue: () => multiValueStyles, | |
| multiValueLabel: () => multiValueLabelStyles, | |
| multiValueRemove: () => multiValueRemoveStyles, | |
| indicatorsContainer: () => indicatorsContainerStyles, | |
| clearIndicator: () => clearIndicatorStyles, | |
| indicatorSeparator: () => indicatorSeparatorStyles, | |
| dropdownIndicator: () => dropdownIndicatorStyles, | |
| groupHeading: () => groupHeadingStyles, | |
| noOptionsMessage: () => noOptionsMessageStyles, | |
| }} | |
| {...props} | |
| /> | |
| </> | |
| ); | |
| }; | |
| 2. Single Select Component with form --------------------------------------------------------------------------------- | |
| const jobTypeList = [ | |
| { value: "Full Time", label: "Full Time" }, | |
| { value: "Part Time", label: "Part Time" }, | |
| { value: "Intern", label: "Intern" }, | |
| { value: "Temporary", label: "Temporary" }, | |
| { value: "Contractor", label: "Contractor" }, | |
| { value: "Volunteer", label: "Volunteer" }, | |
| { value: "Freelance", label: "Freelance" }, | |
| ]; | |
| <FormField | |
| control={form.control} | |
| name="jobType" | |
| render={({ field }) => ( | |
| <FormItem> | |
| <FormLabel>Joy Type</FormLabel> | |
| <FormDescription>Select the job type.</FormDescription> | |
| <SelectComponent | |
| createAble={true} | |
| isMulti={false} | |
| value={field.value} | |
| options={jobTypeList} | |
| onChange={field.onChange} | |
| placeholder="Select Job Type" | |
| {...field} | |
| /> | |
| <FormMessage /> | |
| </FormItem> | |
| )} | |
| /> | |
| 3. Multi Select Component with form --------------------------------------------------------------------------------- | |
| const jobTypeList = [ | |
| { value: "Full Time", label: "Full Time" }, | |
| { value: "Part Time", label: "Part Time" }, | |
| { value: "Intern", label: "Intern" }, | |
| { value: "Temporary", label: "Temporary" }, | |
| { value: "Contractor", label: "Contractor" }, | |
| { value: "Volunteer", label: "Volunteer" }, | |
| { value: "Freelance", label: "Freelance" }, | |
| ]; | |
| <FormField | |
| control={form.control} | |
| name="skills" | |
| render={({ field }) => ( | |
| <FormItem> | |
| <FormLabel>Skills</FormLabel> | |
| <FormDescription>Select the Skills Required.</FormDescription> | |
| <SelectComponent | |
| createAble={true} | |
| isMulti={true} | |
| value={field.value} | |
| options={jobTypeList} | |
| onChange={field.onChange} | |
| placeholder="Select Skills" | |
| {...field} | |
| /> | |
| <FormMessage /> | |
| </FormItem> | |
| )} | |
| /> |
@emredevsalot yes, you can import the react-select prop types
import Select, { type Props as SelectProps } from "react-select";
using this inside a react hook form gives
Warning: Function components cannot be given refs. Attempts to access this ref will fail. Did you mean to use React.forwardRef()?
Check the render method of SlotClone.
@ak274
Currently experiencing the same. Did you manage to do a fix?
https://gist.github.com/ak274/3f38bbdd7810489e6fd77882e46b2387
Use forwardRef to pass ref to your react hook form controller.
Hey i dont know if i missed something but the dropdocn icon is kind of different and also on the txt file some components are not used. Like
`const DropdownIndicator = (props: DropdownIndicatorProps) => {
return (
<components.DropdownIndicator {...props}>
</components.DropdownIndicator>
);
};
const ClearIndicator = (props: ClearIndicatorProps) => {
return (
<components.ClearIndicator {...props}>
</components.ClearIndicator>
);
};
const MultiValueRemove = (props: MultiValueRemoveProps) => {
return (
<components.MultiValueRemove {...props}>
</components.MultiValueRemove>
);
};
`
Hi @amosmachora you need to pass them as props to the Select component Comp itself. That's the way to go about it.
@praizjosh thanks. I fixed it
could u make passable for choosing element by arrow ?
Great implementation. Thank you for that.
I got an error using the options, so I tried to take the type of the original react-select element options.
From
options: any[];to
options: | OptionsOrGroups< { value: string; label: string }, GroupBase<{ value: string; label: string }> > | undefined;That seems to fix the issue, also that got me wondering, is it possible to take all the prop types from the original component rather than creating in
SelectComponentProps?