Simple Search Input
Lightweight search component with real-time filtering and dropdown results.
ReactTailwind CSSTypeScriptResponsiveInput
Live Preview
Interactive
Simple Search Input.tsxLive Code
"use client";
import { useEffect, useRef, useState } from "react";
interface SearchResult {
id: string;
title: string;
category: string;
}
export default function SimpleSearchInput() {
const [query, setQuery] = useState("");
const [isOpen, setIsOpen] = useState(false);
const [results, setResults] = useState<SearchResult[]>([]);
const inputRef = useRef<HTMLInputElement>(null);
const dropdownRef = useRef<HTMLDivElement>(null);
const sampleResults: SearchResult[] = [
{ id: "1", title: "Button Component", category: "Components" },
{ id: "2", title: "Card Component", category: "Components" },
{ id: "3", title: "Modal Component", category: "Components" },
{ id: "4", title: "Landing Page", category: "Templates" },
];
const performSearch = (searchQuery: string) => {
if (!searchQuery.trim()) {
setResults([]);
return;
}
const filteredResults = sampleResults.filter((item) =>
item.title.toLowerCase().includes(searchQuery.toLowerCase())
);
setResults(filteredResults);
};
useEffect(() => {
performSearch(query);
}, [query]);
useEffect(() => {
const handleClickOutside = (event: MouseEvent) => {
if (
dropdownRef.current &&
!dropdownRef.current.contains(event.target as Node) &&
!inputRef.current?.contains(event.target as Node)
) {
setIsOpen(false);
}
};
document.addEventListener("mousedown", handleClickOutside);
return () => document.removeEventListener("mousedown", handleClickOutside);
}, []);
const handleInputChange = (e: React.ChangeEvent<HTMLInputElement>) => {
setQuery(e.target.value);
setIsOpen(true);
};
const clearSearch = () => {
setQuery("");
setResults([]);
inputRef.current?.focus();
};
return (
<div className="w-full max-w-md mx-auto relative">
<div className="relative">
<div className="absolute left-3 top-1\/2 transform -translate-y-1\/2 text-gray-400">
<svg
className="w-4 h-4"
fill="none"
stroke="currentColor"
viewBox="0 0 24 24"
>
<path
strokeLinecap="round"
strokeLinejoin="round"
strokeWidth={2}
d="M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z"
\/>
<\/svg>
<\/div>
<input
ref={inputRef}
type="text"
value={query}
onChange={handleInputChange}
onFocus={() => setIsOpen(true)}
placeholder="Search..."
className="w-full pl-10 pr-10 py-3 border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-blue-500 outline-none"
\/>
{query && (
<button
type="button"
onClick={clearSearch}
className="absolute right-3 top-1\/2 transform -translate-y-1\/2 text-gray-400 hover:text-gray-600"
>
<svg
className="w-4 h-4"
fill="none"
stroke="currentColor"
viewBox="0 0 24 24"
>
<path
strokeLinecap="round"
strokeLinejoin="round"
strokeWidth={2}
d="M6 18L18 6M6 6l12 12"
\/>
<\/svg>
<\/button>
)}
<\/div>
{isOpen && (
<div
ref={dropdownRef}
className="absolute top-full left-0 right-0 mt-1 bg-white border border-gray-200 rounded-lg shadow-lg z-50 max-h-60 overflow-y-auto"
>
{!query ? (
<div className="p-3 text-center text-gray-500 text-sm">
Start typing to search...
<\/div>
) : results.length > 0 ? (
<div className="p-1">
{results.map((result) => (
<button
key={result.id}
onClick={() => {
setIsOpen(false);
console.log(`Selected: ${result.title}`);
}}
className="w-full text-left p-2 hover:bg-gray-50 rounded flex items-center justify-between"
>
<span className="font-medium">{result.title}<\/span>
<span className="text-xs text-gray-500 bg-gray-100 px-2 py-1 rounded">
{result.category}
<\/span>
<\/button>
))}
<\/div>
) : (
<div className="p-3 text-center text-gray-500 text-sm">
No results found
<\/div>
)}
<\/div>
)}
<\/div>
);
}
How to use
- 1. Copy the component code
- 2. Paste it into your React/Next.js project
- 3. Make sure you have Tailwind CSS configured
- 4. Customize colors, spacing, and content as needed
Dependencies
react
^18.0.0tailwindcss
^3.0.0Back to Components
Need complete templates?
View Premium Templates