Search Components
Beautiful search components built with TailwindCSS. Perfect for implementing search functionality, filters, and results display.
1. Simple Search Bar
Clean and minimal search bar with icon and placeholder text.
<!-- Simple Search Bar -->
<div class="relative">
<div class="absolute inset-y-0 left-0 pl-3 flex items-center pointer-events-none">
<svg class="w-5 h-5 text-gray-400" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z"/>
</svg>
</div>
<input type="text" class="w-full pl-10 pr-4 py-3 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-purple-500 focus:border-purple-500" placeholder="Search...">
</div>
<template>
<!-- Simple Search Bar -->
<div class="relative">
<div class="absolute inset-y-0 left-0 pl-3 flex items-center pointer-events-none">
<svg class="w-5 h-5 text-gray-400" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z"/>
</svg>
</div>
<input type="text" class="w-full pl-10 pr-4 py-3 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-purple-500 focus:border-purple-500" placeholder="Search...">
</div>
</template>
export default function SimpleSearchBar() {
return (
<div className="relative">
<div className="absolute inset-y-0 left-0 pl-3 flex items-center pointer-events-none">
<svg className="w-5 h-5 text-gray-400" 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
type="text"
className="w-full pl-10 pr-4 py-3 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-purple-500 focus:border-purple-500"
placeholder="Search..."
/>
</div>
);
}
2. Search with Suggestions
Search bar with dropdown suggestions that appear as you type.
<!-- Search with Suggestions -->
<div x-data="{ query: '', suggestions: ['Apple', 'Banana', 'Cherry', 'Date', 'Elderberry'], showSuggestions: false }">
<div class="relative">
<div class="absolute inset-y-0 left-0 pl-3 flex items-center pointer-events-none">
<svg class="w-5 h-5 text-gray-400" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z"/>
</svg>
</div>
<input type="text" x-model="query" @focus="showSuggestions = true" @blur="setTimeout(() => showSuggestions = false, 200)" class="w-full pl-10 pr-4 py-3 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-purple-500 focus:border-purple-500" placeholder="Search fruits...">
<div x-show="showSuggestions && query" class="absolute top-full left-0 right-0 bg-white border border-gray-300 rounded-b-lg shadow-lg z-10">
<template x-for="suggestion in suggestions.filter(s => s.toLowerCase().includes(query.toLowerCase()))" :key="suggestion">
<div class="px-4 py-2 hover:bg-gray-100 cursor-pointer" x-text="suggestion"></div>
</template>
</div>
</div>
</div>
<template>
<!-- Search with Suggestions -->
<div>
<div class="relative">
<div class="absolute inset-y-0 left-0 pl-3 flex items-center pointer-events-none">
<svg class="w-5 h-5 text-gray-400" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z"/>
</svg>
</div>
<input type="text" v-model="query" @focus="showSuggestions = true" @blur="setTimeout(() => showSuggestions = false, 200)" class="w-full pl-10 pr-4 py-3 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-purple-500 focus:border-purple-500" placeholder="Search fruits...">
<div v-if="showSuggestions && query" class="absolute top-full left-0 right-0 bg-white border border-gray-300 rounded-b-lg shadow-lg z-10">
<div v-for="suggestion in suggestions.filter(s => s.toLowerCase().includes(query.toLowerCase()))" :key="suggestion" class="px-4 py-2 hover:bg-gray-100 cursor-pointer">
{{ suggestion }}
</div>
</div>
</div>
</div>
</template>
<script setup>
import { ref } from 'vue'
const query = ref('')
const suggestions = ref(['Apple', 'Banana', 'Cherry', 'Date', 'Elderberry'])
const showSuggestions = ref(false)
</script>
import React, { useState } from 'react'
export default function SearchWithSuggestions() {
const [query, setQuery] = useState('')
const [showSuggestions, setShowSuggestions] = useState(false)
const suggestions = ['Apple', 'Banana', 'Cherry', 'Date', 'Elderberry']
const filteredSuggestions = suggestions.filter(s =>
s.toLowerCase().includes(query.toLowerCase())
)
return (
<div className="relative">
<div className="absolute inset-y-0 left-0 pl-3 flex items-center pointer-events-none">
<svg className="w-5 h-5 text-gray-400" 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
type="text"
value={query}
onChange={(e) => setQuery(e.target.value)}
onFocus={() => setShowSuggestions(true)}
onBlur={() => setTimeout(() => setShowSuggestions(false), 200)}
className="w-full pl-10 pr-4 py-3 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-purple-500 focus:border-purple-500"
placeholder="Search fruits..."
/>
{showSuggestions && query && (
<div className="absolute top-full left-0 right-0 bg-white border border-gray-300 rounded-b-lg shadow-lg z-10">
{filteredSuggestions.map((suggestion, index) => (
<div key={index} className="px-4 py-2 hover:bg-gray-100 cursor-pointer">
{suggestion}
</div>
))}
</div>
)}
</div>
);
}
3. Advanced Search Filter
Search bar with category and price filters for more precise results.
<!-- Advanced Search Filter -->
<div x-data="{ searchTerm: '', category: 'all', priceRange: 'all' }">
<div class="w-full max-w-2xl space-y-4">
<div class="relative">
<div class="absolute inset-y-0 left-0 pl-3 flex items-center pointer-events-none">
<svg class="w-5 h-5 text-gray-400" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z"/>
</svg>
</div>
<input type="text" x-model="searchTerm" class="w-full pl-10 pr-4 py-3 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-purple-500 focus:border-purple-500" placeholder="Search products...">
</div>
<div class="flex space-x-4">
<select x-model="category" class="px-3 py-2 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-purple-500 focus:border-purple-500">
<option value="all">All Categories</option>
<option value="electronics">Electronics</option>
<option value="clothing">Clothing</option>
<option value="books">Books</option>
</select>
<select x-model="priceRange" class="px-3 py-2 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-purple-500 focus:border-purple-500">
<option value="all">All Prices</option>
<option value="0-50">$0 - $50</option>
<option value="50-100">$50 - $100</option>
<option value="100+">$100+</option>
</select>
</div>
</div>
</div>
<template>
<!-- Advanced Search Filter -->
<div>
<div class="w-full max-w-2xl space-y-4">
<div class="relative">
<div class="absolute inset-y-0 left-0 pl-3 flex items-center pointer-events-none">
<svg class="w-5 h-5 text-gray-400" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z"/>
</svg>
</div>
<input type="text" v-model="searchTerm" class="w-full pl-10 pr-4 py-3 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-purple-500 focus:border-purple-500" placeholder="Search products...">
</div>
<div class="flex space-x-4">
<select v-model="category" class="px-3 py-2 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-purple-500 focus:border-purple-500">
<option value="all">All Categories</option>
<option value="electronics">Electronics</option>
<option value="clothing">Clothing</option>
<option value="books">Books</option>
</select>
<select v-model="priceRange" class="px-3 py-2 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-purple-500 focus:border-purple-500">
<option value="all">All Prices</option>
<option value="0-50">$0 - $50</option>
<option value="50-100">$50 - $100</option>
<option value="100+">$100+</option>
</select>
</div>
</div>
</div>
</template>
<script setup>
import { ref } from 'vue'
const searchTerm = ref('')
const category = ref('all')
const priceRange = ref('all')
</script>
import React, { useState } from 'react'
export default function AdvancedSearchFilter() {
const [searchTerm, setSearchTerm] = useState('')
const [category, setCategory] = useState('all')
const [priceRange, setPriceRange] = useState('all')
return (
<div className="w-full max-w-2xl space-y-4">
<div className="relative">
<div className="absolute inset-y-0 left-0 pl-3 flex items-center pointer-events-none">
<svg className="w-5 h-5 text-gray-400" 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
type="text"
value={searchTerm}
onChange={(e) => setSearchTerm(e.target.value)}
className="w-full pl-10 pr-4 py-3 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-purple-500 focus:border-purple-500"
placeholder="Search products..."
/>
</div>
<div className="flex space-x-4">
<select
value={category}
onChange={(e) => setCategory(e.target.value)}
className="px-3 py-2 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-purple-500 focus:border-purple-500"
>
<option value="all">All Categories</option>
<option value="electronics">Electronics</option>
<option value="clothing">Clothing</option>
<option value="books">Books</option>
</select>
<select
value={priceRange}
onChange={(e) => setPriceRange(e.target.value)}
className="px-3 py-2 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-purple-500 focus:border-purple-500"
>
<option value="all">All Prices</option>
<option value="0-50">$0 - $50</option>
<option value="50-100">$50 - $100</option>
<option value="100+">$100+</option>
</select>
</div>
</div>
);
}
4. Floating Label Search
Search input with a floating label that animates when focused or filled.
<!-- Floating Label Search -->
<div class="relative">
<input type="text" class="w-full px-4 py-3 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-purple-500 focus:border-purple-500 peer" placeholder=" ">
<label class="absolute left-4 top-3 text-gray-500 transition-all duration-200 peer-focus:top-1 peer-focus:text-sm peer-focus:text-purple-600 peer-[:not(:placeholder-shown)]:top-1 peer-[:not(:placeholder-shown)]:text-sm peer-[:not(:placeholder-shown)]:text-purple-600">Search...</label>
<div class="absolute inset-y-0 right-0 pr-3 flex items-center pointer-events-none">
<svg class="w-5 h-5 text-gray-400" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z"/>
</svg>
</div>
</div>
<template>
<!-- Floating Label Search -->
<div class="relative">
<input type="text" v-model="searchTerm" class="w-full px-4 py-3 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-purple-500 focus:border-purple-500 peer" placeholder=" ">
<label class="absolute left-4 top-3 text-gray-500 transition-all duration-200 peer-focus:top-1 peer-focus:text-sm peer-focus:text-purple-600 peer-[:not(:placeholder-shown)]:top-1 peer-[:not(:placeholder-shown)]:text-sm peer-[:not(:placeholder-shown)]:text-purple-600">Search...</label>
<div class="absolute inset-y-0 right-0 pr-3 flex items-center pointer-events-none">
<svg class="w-5 h-5 text-gray-400" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z"/>
</svg>
</div>
</div>
</template>
<script setup>
import { ref } from 'vue'
const searchTerm = ref('')
</script>
import React, { useState } from 'react'
export default function FloatingLabelSearch() {
const [searchTerm, setSearchTerm] = useState('')
return (
<div className="relative">
<input
type="text"
value={searchTerm}
onChange={(e) => setSearchTerm(e.target.value)}
className="w-full px-4 py-3 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-purple-500 focus:border-purple-500 peer"
placeholder=" "
/>
<label className="absolute left-4 top-3 text-gray-500 transition-all duration-200 peer-focus:top-1 peer-focus:text-sm peer-focus:text-purple-600 peer-[:not(:placeholder-shown)]:top-1 peer-[:not(:placeholder-shown)]:text-sm peer-[:not(:placeholder-shown)]:text-purple-600">Search...</label>
<div className="absolute inset-y-0 right-0 pr-3 flex items-center pointer-events-none">
<svg className="w-5 h-5 text-gray-400" 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>
</div>
);
}
5. Search Modal
Modal-based search interface that opens on trigger with search functionality.
<!-- Search Modal -->
<div x-data="{ isOpen: false, searchTerm: '', results: ['Apple iPhone 14', 'Samsung Galaxy S23', 'Nike Air Max', 'The Great Gatsby'], get filteredResults() { return this.results.filter(r => r.toLowerCase().includes(this.searchTerm.toLowerCase())) } }">
<button @click="isOpen = true" class="w-full px-4 py-3 border border-gray-300 rounded-lg bg-white hover:bg-gray-50 focus:outline-none focus:ring-2 focus:ring-purple-500 focus:border-purple-500 flex items-center justify-between">
<span class="text-gray-500">Search...</span>
<svg class="w-5 h-5 text-gray-400" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z"/>
</svg>
</button>
<!-- Modal -->
<div x-show="isOpen" class="fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center z-50" @click="isOpen = false">
<div class="bg-white rounded-lg shadow-xl max-w-md w-full mx-4" @click.stop>
<div class="p-4 border-b border-gray-200">
<div class="relative">
<input type="text" x-model="searchTerm" class="w-full pl-10 pr-4 py-3 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-purple-500 focus:border-purple-500" placeholder="Search...">
<div class="absolute inset-y-0 left-0 pl-3 flex items-center pointer-events-none">
<svg class="w-5 h-5 text-gray-400" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z"/>
</svg>
</div>
</div>
</div>
<div class="max-h-64 overflow-y-auto">
<template x-for="result in filteredResults" :key="result">
<div class="px-4 py-3 hover:bg-gray-100 cursor-pointer border-b border-gray-100 last:border-b-0" x-text="result"></div>
</template>
</div>
<div class="p-4 border-t border-gray-200">
<button @click="isOpen = false" class="w-full px-4 py-2 bg-purple-600 text-white rounded-lg hover:bg-purple-700 transition-colors">Close</button>
</div>
</div>
</div>
</div>
<template>
<!-- Search Modal -->
<div>
<button @click="isOpen = true" class="w-full px-4 py-3 border border-gray-300 rounded-lg bg-white hover:bg-gray-50 focus:outline-none focus:ring-2 focus:ring-purple-500 focus:border-purple-500 flex items-center justify-between">
<span class="text-gray-500">Search...</span>
<svg class="w-5 h-5 text-gray-400" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z"/>
</svg>
</button>
<!-- Modal -->
<div v-if="isOpen" class="fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center z-50" @click="isOpen = false">
<div class="bg-white rounded-lg shadow-xl max-w-md w-full mx-4" @click.stop>
<div class="p-4 border-b border-gray-200">
<div class="relative">
<input type="text" v-model="searchTerm" class="w-full pl-10 pr-4 py-3 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-purple-500 focus:border-purple-500" placeholder="Search...">
<div class="absolute inset-y-0 left-0 pl-3 flex items-center pointer-events-none">
<svg class="w-5 h-5 text-gray-400" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z"/>
</svg>
</div>
</div>
</div>
<div class="max-h-64 overflow-y-auto">
<div v-for="result in filteredResults" :key="result" class="px-4 py-3 hover:bg-gray-100 cursor-pointer border-b border-gray-100 last:border-b-0">
{{ result }}
</div>
</div>
<div class="p-4 border-t border-gray-200">
<button @click="isOpen = false" class="w-full px-4 py-2 bg-purple-600 text-white rounded-lg hover:bg-purple-700 transition-colors">Close</button>
</div>
</div>
</div>
</div>
</template>
<script setup>
import { ref, computed } from 'vue'
const isOpen = ref(false)
const searchTerm = ref('')
const results = ref(['Apple iPhone 14', 'Samsung Galaxy S23', 'Nike Air Max', 'The Great Gatsby'])
const filteredResults = computed(() => {
if (!searchTerm.value) return results.value
return results.value.filter(r => r.toLowerCase().includes(searchTerm.value.toLowerCase()))
})
</script>
import React, { useState, useMemo } from 'react'
export default function SearchModal() {
const [isOpen, setIsOpen] = useState(false)
const [searchTerm, setSearchTerm] = useState('')
const results = ['Apple iPhone 14', 'Samsung Galaxy S23', 'Nike Air Max', 'The Great Gatsby']
const filteredResults = useMemo(() => {
if (!searchTerm) return results
return results.filter(r => r.toLowerCase().includes(searchTerm.toLowerCase()))
}, [searchTerm, results])
return (
<div>
<button onClick={() => setIsOpen(true)} className="w-full px-4 py-3 border border-gray-300 rounded-lg bg-white hover:bg-gray-50 focus:outline-none focus:ring-2 focus:ring-purple-500 focus:border-purple-500 flex items-center justify-between">
<span className="text-gray-500">Search...</span>
<svg className="w-5 h-5 text-gray-400" 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>
</button>
{isOpen && (
<div className="fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center z-50" onClick={() => setIsOpen(false)}>
<div className="bg-white rounded-lg shadow-xl max-w-md w-full mx-4" onClick={(e) => e.stopPropagation()}>
<div className="p-4 border-b border-gray-200">
<div className="relative">
<input
type="text"
value={searchTerm}
onChange={(e) => setSearchTerm(e.target.value)}
className="w-full pl-10 pr-4 py-3 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-purple-500 focus:border-purple-500"
placeholder="Search..."
/>
<div className="absolute inset-y-0 left-0 pl-3 flex items-center pointer-events-none">
<svg className="w-5 h-5 text-gray-400" 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>
</div>
</div>
<div className="max-h-64 overflow-y-auto">
{filteredResults.map((result, index) => (
<div key={index} className="px-4 py-3 hover:bg-gray-100 cursor-pointer border-b border-gray-100 last:border-b-0">
{result}
</div>
))}
</div>
<div className="p-4 border-t border-gray-200">
<button onClick={() => setIsOpen(false)} className="w-full px-4 py-2 bg-purple-600 text-white rounded-lg hover:bg-purple-700 transition-colors">Close</button>
</div>
</div>
</div>
)}
</div>
);
}