Skip to content

Instantly share code, notes, and snippets.

@omeralpi
Last active October 24, 2024 15:51
Show Gist options
  • Select an option

  • Save omeralpi/65fabb7498eba1578c22b6b69c2eb471 to your computer and use it in GitHub Desktop.

Select an option

Save omeralpi/65fabb7498eba1578c22b6b69c2eb471 to your computer and use it in GitHub Desktop.
Infinite Scroll Select Component with shadcn/ui in React
import { cn } from "@/lib/utils";
import { Check, ChevronsUpDown } from "lucide-react";
import * as React from 'react';
import { Button } from "./ui/button";
import {
Command,
CommandEmpty,
CommandGroup,
CommandInput,
CommandItem,
CommandList,
} from "./ui/command";
import { Popover, PopoverContent, PopoverTrigger } from "./ui/popover";
export function InfiniteSelect({
options = [],
value,
onChangeValue,
placeholder = "Seçiniz",
}: {
options: Array<{ value: string; label: string }>;
value: string;
onChangeValue: (value: string) => void;
placeholder?: string;
}) {
const [open, setOpen] = React.useState(false);
const [search, setSearch] = React.useState("");
const [displayCount, setDisplayCount] = React.useState(100);
const selectedOption = options.find((option) => option.value === value);
const filteredOptions = options
.filter((option) => option.label.toLowerCase().includes(search.toLowerCase()))
.slice(0, displayCount);
const onScroll = (e: React.UIEvent<HTMLDivElement>) => {
const { scrollTop, scrollHeight, clientHeight } = e.currentTarget;
if (scrollTop + clientHeight >= scrollHeight - 5) {
setDisplayCount((prev) => prev + 100);
}
};
React.useEffect(() => {
setDisplayCount(100);
}, [search]);
return (
<Popover open={open} onOpenChange={setOpen}>
<PopoverTrigger asChild>
<Button
variant="outline"
role="combobox"
aria-expanded={open}
className="w-[200px] justify-between"
>
<span
className={cn(
"font-normal text-left",
!selectedOption && "text-muted-foreground"
)}
>
{selectedOption ? selectedOption.label : placeholder}
</span>
<ChevronsUpDown className="ml-2 h-4 w-4 shrink-0 opacity-50" />
</Button>
</PopoverTrigger>
<PopoverContent className="w-[200px] p-0">
<Command shouldFilter={false}>
<CommandInput
value={search}
onValueChange={setSearch}
placeholder="Search"
/>
<CommandList onScroll={onScroll}>
<CommandEmpty>
No found
</CommandEmpty>
<CommandGroup>
{filteredOptions.map((option) => (
<CommandItem
key={option.value}
value={option.label}
onSelect={() => {
onChangeValue?.(option.value);
setOpen(false);
}}
>
<Check
className={cn(
"mr-2 h-4 w-4",
value === option.value ? "opacity-100" : "opacity-0"
)}
/>
{option.label}
</CommandItem>
))}
</CommandGroup>
</CommandList>
</Command>
</PopoverContent>
</Popover>
);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment