Skip to content

Instantly share code, notes, and snippets.

@saturngod
Created December 9, 2025 15:59
Show Gist options
  • Select an option

  • Save saturngod/eaa487e593ba97cfd914c9f4ab09175c to your computer and use it in GitHub Desktop.

Select an option

Save saturngod/eaa487e593ba97cfd914c9f4ab09175c to your computer and use it in GitHub Desktop.
shadcn ui autocomplete
import { useState, useEffect, useRef, useCallback } from "react"
import axios from "axios"
import { Check } from "lucide-react"
import { cn } from "@/lib/utils"
import { Input } from "@/components/ui/input"
import {
Command,
CommandGroup,
CommandItem,
CommandList,
} from "@/components/ui/command"
interface Country {
name: string
}
export function AutocompleteSearch() {
const [inputValue, setInputValue] = useState("")
const [results, setResults] = useState<Country[]>([])
const [open, setOpen] = useState(false)
const inputRef = useRef<HTMLInputElement>(null)
useEffect(() => {
if (!inputValue) {
setResults([])
setOpen(false)
return
}
const fetchResults = async () => {
try {
const response = await axios.get(`http://127.0.0.1:8001/loc/${inputValue}`)
if (response.data && response.data.result) {
setResults(response.data.result)
setOpen(true)
} else {
setOpen(false)
}
} catch (error) {
console.error("Error fetching data", error)
setResults([])
}
}
const timer = setTimeout(() => {
fetchResults()
}, 300)
return () => clearTimeout(timer)
}, [inputValue])
const handleSelect = useCallback((currentValue: string) => {
setInputValue(currentValue)
setOpen(false)
inputRef.current?.focus()
}, [])
const handleBlur = () => {
// Small delay to allow click event on item to fire before closing
setTimeout(() => {
setOpen(false)
}, 200)
}
const handleFocus = () => {
if (inputValue && results.length > 0) {
setOpen(true)
}
}
return (
<div className="w-full max-w-sm px-4 relative">
<label className="text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70 mb-2 block text-gray-700">
Search Country
</label>
<div className="relative group">
<Input
ref={inputRef}
placeholder="Type to search..."
value={inputValue}
onChange={(e) => setInputValue(e.target.value)}
onBlur={handleBlur}
onFocus={handleFocus}
/>
{open && results.length > 0 && (
<div className="absolute top-full left-0 w-full mt-1 bg-white border rounded-md shadow-lg z-50 overflow-hidden animate-in fade-in-0 zoom-in-95">
<Command>
<CommandList>
<CommandGroup heading="Suggestions">
{results.map((country) => (
<CommandItem
key={country.name}
value={country.name}
onSelect={handleSelect}
className="cursor-pointer"
>
<Check
className={cn(
"mr-2 h-4 w-4",
inputValue === country.name ? "opacity-100" : "opacity-0"
)}
/>
{country.name}
</CommandItem>
))}
</CommandGroup>
</CommandList>
</Command>
</div>
)}
</div>
</div>
)
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment