Patterns
Search Results
A search UI combining a type-ahead input, command palette, and filterable result cards with empty-state fallback.
Preview
Getting Started with Visor
/docs/getting-started
Learn how to install and configure Visor in your Next.js project in under five minutes.
Button Component
/docs/components/button
The Button component supports multiple variants including primary, outline, ghost, and destructive.
Theme Architecture
/docs/tokens/themes
Visor's three-tier token architecture separates primitives, semantic tokens, and adaptive theme values.
Design Token Rules
/docs/tokens/rules
Token rules enforce consistent spacing, shadow, motion, and color usage across all components.
When to Use
- Search pages where users need to filter and browse a large dataset
- When combining free-text search with faceted category filters
- Directory, catalog, or discovery interfaces with card-based result display
Components Used
Structure
<div className="search-layout">
<div className="search-controls">
<SearchInput
value={query}
onChange={setQuery}
placeholder="Search items..."
onClear={() => setQuery("")}
/>
<Combobox
options={categoryOptions}
value={selectedCategory}
onValueChange={setSelectedCategory}
placeholder="All categories"
/>
</div>
<Command shouldFilter={false}>
<CommandList>
{isLoading && (
<CommandEmpty>Searching...</CommandEmpty>
)}
{!isLoading && results.length === 0 && (
<EmptyState
icon={<MagnifyingGlassIcon />}
title="No results found"
description={`No items match "${query}". Try a different search term.`}
/>
)}
{!isLoading && results.length > 0 && (
<CommandGroup heading={`${results.length} results`}>
{results.map((item) => (
<CommandItem key={item.id} onSelect={() => navigate(item.href)}>
<Card className="search-result-card">
<CardHeader>
<CardTitle>{item.title}</CardTitle>
<Badge variant="secondary">{item.category}</Badge>
</CardHeader>
<CardContent>
<p>{item.description}</p>
</CardContent>
</Card>
</CommandItem>
))}
</CommandGroup>
)}
</CommandList>
</Command>
</div>Notes
- Pass
shouldFilter={false}to Command when search is server-side or debounced. - SearchInput provides the clear button and search icon affordance; avoid reimplementing in plain Input.
- EmptyState handles the zero-results case — do not use a bare paragraph.
- Combobox for category filter is preferred over Select when the option list may be long or searchable.