Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Save ArielMejiaDev/c4f256742593b04d4f3ccac2e2cef8e6 to your computer and use it in GitHub Desktop.
Save ArielMejiaDev/c4f256742593b04d4f3ccac2e2cef8e6 to your computer and use it in GitHub Desktop.
A "simplified" "form-like-style" "stylable" version of Shadcn UI combobox examples.
/*
Author: Javier Antonio Llanos Marriaga
Github: @javierllns
LinkedIn: https://www.linkedin.com/in/javierllns/
Portfolio: https://javierllns.github.io/
-
File name: ShadcnSimplifiedCombobox.tsx
Description: A "simplified" "form-like-style" "stylable" version of Shadcn UI combobox examples.
License: MIT
-
Note: If this code has been helpful or inspiration for you, please let me know :).
*/
import { useState, ReactNode } from 'react'
import { cn } from '@components/lib/utils'
import { Popover, PopoverContent, PopoverTrigger } from '@components/lib/ui/popover'
import {
Command,
CommandEmpty,
CommandGroup,
CommandInput,
CommandItem,
CommandList
} from '@components/lib/ui/command'
export interface ComboboxOptionType {
label: string
value: string
}
export type ComboboxOptionsType = Array<ComboboxOptionType>
function ComboboxRoot({
children,
open,
onOpenChange
}: {
children: ReactNode
open: boolean
onOpenChange: React.Dispatch<React.SetStateAction<boolean>>
}): JSX.Element {
return (
<Popover open={open} onOpenChange={onOpenChange}>
{children}
</Popover>
)
}
function ComboboxTrigger({ children }: { children: ReactNode }): JSX.Element {
return <PopoverTrigger asChild>{children}</PopoverTrigger>
}
function ComboboxContent({
children,
inputPlaceHolder = 'Search option...',
notFoundMessage = 'No option found.',
className = ''
}: {
children?: ReactNode
inputPlaceHolder?: string
notFoundMessage?: string
className?: string
}): JSX.Element {
return (
<PopoverContent className={cn('w-[200px] p-0', className)}>
<Command>
<CommandInput placeholder={inputPlaceHolder} />
<CommandList>
<CommandEmpty>{notFoundMessage}</CommandEmpty>
<CommandGroup>{children}</CommandGroup>
</CommandList>
</Command>
</PopoverContent>
)
}
function Combobox({
options = [],
placeHolderMessage = 'Select option...',
searchPlaceHolderMessage = 'Search option...',
notFoundMessage = 'No option found.',
render
}: {
options: ComboboxOptionsType
placeHolderMessage?: string
searchPlaceHolderMessage?: string
notFoundMessage?: string
render: (ctx: {
options: ComboboxOptionsType
placeHolderMessage: string
searchPlaceHolderMessage: string
notFoundMessage: string
open: boolean
setOpen: React.Dispatch<React.SetStateAction<boolean>>
value: string
setValue: React.Dispatch<React.SetStateAction<string>>
}) => JSX.Element
}) {
const [open, setOpen] = useState(false)
const [value, setValue] = useState('')
return render({
options,
placeHolderMessage,
searchPlaceHolderMessage,
notFoundMessage,
open,
setOpen,
value,
setValue
})
}
export { Combobox, ComboboxRoot, ComboboxTrigger, ComboboxContent, CommandItem as ComboboxItem }
//!USAGE:
/*
? export const SampleCombobox: FC = () => {
? return (
? <div>
? <Combobox
? options={frameworks}
? placeHolderMessage='Please Select an option...''
? searchPlaceHolderMessage='Please Search for an option...'
? notFoundMessage='Ups!, No option found. :('
? render={(ctx) => {
? return (
? <ComboboxRoot open={ctx.open} onOpenChange={ctx.setOpen}>
? <ComboboxTrigger>
? <Button
? className='w-[200px] justify-between'
? variant='outline'
? role='combobox'
? aria-expanded={ctx.open}
? >
? {ctx.value
? ? ctx.options.find((opt) => opt.value === ctx.value)?.label
? : ctx.placeHolderMessage}
? <ChevronsUpDown className='ml-2 h-4 w-4 shrink-0 opacity-50' />
? </Button>
? </ComboboxTrigger>
?
? <ComboboxContent
? className='w-[200px]'
? inputPlaceHolder={ctx.searchPlaceHolderMessage}
? notFoundMessage={ctx.notFoundMessage}
? >
? {ctx.options.map((opt) => (
? <ComboboxItem
? key={opt.value}
? value={opt.value}
? onSelect={(currentValue) => {
? ctx.setValue(currentValue === ctx.value ? '' : currentValue)
? ctx.setOpen(false)
? }}
? >
? <Check
? className={cn(
? 'mr-2 h-4 w-4',
? ctx.value === opt.value ? 'opacity-100' : 'opacity-0'
? )}
? />
? {opt.label}
? </ComboboxItem>
? ))}
? </ComboboxContent>
? </ComboboxRoot>
? )
? }}
? />
? </div>
? )
? }
*/
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment