Search
Global search results view component
Search
The Search view provides a unified interface for searching across all resources, collections, and content in the application. It supports filtering, result grouping, and intelligent suggestions.
Type Signature
interface SearchViewProps {
/** Page title */
title?: string
/** Page description */
description?: string
/** View layout mode */
layout?: 'single' | 'column' | 'canvas' | 'vibe'
/** Search query */
query?: string
/** Search results */
results?: Array<{
id: string
type: string
title: string
description?: string
url: string
metadata?: Record<string, any>
}>
/** Filter by type */
filters?: Record<string, any>
/** Total results count */
total?: number
/** Show suggestions */
showSuggestions?: boolean
/** Page-level action buttons */
actions?: Array<{
id: string
label: string
icon?: string
onClick?: () => void
variant?: 'default' | 'primary' | 'destructive'
}>
/** Loading state */
loading?: boolean
/** Error state */
error?: string
/** Child content */
children?: React.ReactNode
}Usage
<App name="Acme Dashboard">
<Shell>
<SearchView
query="project alpha"
results={searchResults}
total={42}
showSuggestions={true}
filters={{
type: ['projects', 'tasks'],
status: 'active'
}}
/>
</Shell>
</App>Props
title
The page title displayed in the header. Defaults to "Search Results".
<SearchView
title="Search"
query="project alpha"
>description
Optional page description.
<SearchView
title="Search"
description="Search across projects, tasks, and documents"
>layout
Layout mode for the search content. Defaults to 'single'.
// Single column list (default)
<SearchView layout="single">
// Multi-column layout with filters
<SearchView layout="column">query
The search query string entered by the user.
<SearchView
query="project alpha"
results={results}
/>results
Array of search result items.
<SearchView
query="dashboard"
results={[
{
id: 'page_1',
type: 'page',
title: 'Dashboard Overview',
description: 'Main dashboard with metrics and charts',
url: '/dashboard',
metadata: {
lastModified: '2024-01-15',
author: 'Jane Doe'
}
},
{
id: 'task_2',
type: 'task',
title: 'Update Dashboard Metrics',
description: 'Refresh the dashboard KPIs',
url: '/tasks/123',
metadata: {
status: 'in-progress',
assignee: 'John Smith'
}
},
{
id: 'doc_3',
type: 'document',
title: 'Dashboard Design Specs',
description: 'Design specifications for the dashboard',
url: '/docs/dashboard-specs',
metadata: {
category: 'design',
tags: ['dashboard', 'ui']
}
}
]}
/>filters
Active search filters by field.
<SearchView
query="project"
filters={{
type: ['projects', 'tasks'],
status: 'active',
assignee: 'me'
}}
results={filteredResults}
/>total
Total number of matching results (for pagination).
<SearchView
query="project"
results={results.slice(0, 20)}
total={156}
>
{/* Showing 1-20 of 156 results */}
</SearchView>showSuggestions
Display search suggestions and autocomplete. Defaults to true.
<SearchView
query="proj"
showSuggestions={true}
>
<SearchSuggestions
suggestions={[
'project alpha',
'project beta',
'project management'
]}
/>
</SearchView>actions
Page-level action buttons.
<SearchView
query="project"
actions={[
{
id: 'save-search',
label: 'Save Search',
icon: 'Bookmark',
onClick: () => saveSearch()
},
{
id: 'export',
label: 'Export Results',
icon: 'Download',
onClick: () => exportResults()
}
]}
/>Search Input
Provide search input component:
<SearchView query={query}>
<SearchInput
value={query}
onChange={setQuery}
onSearch={handleSearch}
placeholder="Search projects, tasks, documents..."
autoFocus={true}
/>
</SearchView>Result Grouping
Group results by type or category:
<SearchView query="design">
<SearchResults>
<ResultGroup title="Projects" count={5}>
{projectResults.map((result) => (
<SearchResult key={result.id} {...result} />
))}
</ResultGroup>
<ResultGroup title="Tasks" count={12}>
{taskResults.map((result) => (
<SearchResult key={result.id} {...result} />
))}
</ResultGroup>
<ResultGroup title="Documents" count={8}>
{docResults.map((result) => (
<SearchResult key={result.id} {...result} />
))}
</ResultGroup>
</SearchResults>
</SearchView>Filters
Provide filter controls:
<SearchView
query={query}
filters={filters}
layout="column"
>
<SearchFilters
filters={[
{
id: 'type',
label: 'Type',
options: [
{ value: 'projects', label: 'Projects', count: 5 },
{ value: 'tasks', label: 'Tasks', count: 12 },
{ value: 'documents', label: 'Documents', count: 8 }
]
},
{
id: 'status',
label: 'Status',
options: [
{ value: 'active', label: 'Active', count: 15 },
{ value: 'completed', label: 'Completed', count: 10 }
]
}
]}
onChange={setFilters}
/>
<SearchResults results={filteredResults} />
</SearchView>Search Suggestions
Show autocomplete and suggestions:
<SearchView
query={query}
showSuggestions={true}
>
{query.length > 0 && (
<SearchSuggestions
suggestions={[
{ text: 'project alpha', type: 'recent' },
{ text: 'project beta', type: 'suggestion' },
{ text: 'projects', type: 'category' }
]}
onSelect={handleSuggestionClick}
/>
)}
</SearchView>Recent Searches
Display recent search history:
<SearchView query="">
<RecentSearches
searches={[
{ query: 'project alpha', timestamp: '2 hours ago' },
{ query: 'dashboard', timestamp: '1 day ago' },
{ query: 'design specs', timestamp: '3 days ago' }
]}
onSelect={setQuery}
onClear={clearHistory}
/>
</SearchView>Empty States
Handle no results gracefully:
<SearchView query={query} results={results}>
{results.length === 0 ? (
<EmptyState
icon="Search"
title="No results found"
description={`No results for "${query}". Try different keywords.`}
action={{
label: 'Clear Search',
onClick: () => setQuery('')
}}
/>
) : (
<SearchResults results={results} />
)}
</SearchView>Highlighting
Highlight matching terms in results:
<SearchResult
title={highlightMatches(result.title, query)}
description={highlightMatches(result.description, query)}
/>Sorting
Allow sorting search results:
<SearchView
query={query}
results={sortedResults}
>
<SearchSort
value={sortBy}
onChange={setSortBy}
options={[
{ value: 'relevance', label: 'Relevance' },
{ value: 'date', label: 'Date Modified' },
{ value: 'title', label: 'Title' }
]}
/>
</SearchView>Pagination
Handle large result sets:
<SearchView
query={query}
results={paginatedResults}
total={totalResults}
>
<SearchResults results={paginatedResults} />
<Pagination
current={currentPage}
total={totalPages}
onChange={setCurrentPage}
/>
</SearchView>App Type Specializations
DeveloperApp Search
Search API docs, endpoints, and logs:
<SearchView
query="authentication"
results={[
{
type: 'endpoint',
title: 'POST /auth/login',
description: 'Authenticate user and return token',
url: '/docs/api/auth#login'
},
{
type: 'guide',
title: 'Authentication Guide',
description: 'How to authenticate API requests',
url: '/docs/guides/auth'
}
]}
/>AdminApp Search
Search users, roles, and settings:
<SearchView
query="admin"
filters={{ type: ['users', 'roles'] }}
results={[
{
type: 'user',
title: 'Jane Admin',
description: 'admin@acme.com',
url: '/users/123'
},
{
type: 'role',
title: 'Administrator',
description: 'Full system access',
url: '/roles/admin'
}
]}
/>CRMApp Search
Search contacts, companies, and deals:
<SearchView
query="acme"
results={[
{
type: 'company',
title: 'Acme Corporation',
description: '$1.2M in pipeline',
url: '/companies/acme'
},
{
type: 'deal',
title: 'Acme - Enterprise License',
description: '$50K, Closing Q1',
url: '/deals/123'
}
]}
/>Advanced Search
Provide advanced search options:
<SearchView query={query}>
<AdvancedSearch
onSearch={handleAdvancedSearch}
fields={[
{ name: 'title', label: 'Title', type: 'text' },
{ name: 'type', label: 'Type', type: 'select', options: [...] },
{ name: 'dateRange', label: 'Date Range', type: 'daterange' },
{ name: 'tags', label: 'Tags', type: 'multiselect' }
]}
/>
</SearchView>Saved Searches
Allow saving and loading searches:
<SearchView
query={query}
filters={filters}
actions={[
{
id: 'save',
label: 'Save Search',
onClick: () => saveSearch({ query, filters })
}
]}
>
<SavedSearches
searches={savedSearches}
onSelect={loadSearch}
onDelete={deleteSearch}
/>
</SearchView>Keyboard Shortcuts
Implement keyboard navigation:
useEffect(() => {
const handleKeyPress = (e: KeyboardEvent) => {
if (e.key === '/') {
e.preventDefault()
focusSearchInput()
}
}
window.addEventListener('keypress', handleKeyPress)
return () => window.removeEventListener('keypress', handleKeyPress)
}, [])
<SearchView
query={query}
aria-label="Press / to search"
>Responsive Behavior
Search adapts to screen size:
Desktop (≥1024px)
┌─────────────────────────────────────┐
│ [Search____________] [Filters ▼] │
├──────────┬──────────────────────────┤
│ │ Projects (5) │
│ Filters │ • Project Alpha │
│ [x] Type │ • Project Beta │
│ Projects │
│ Tasks │ Tasks (12) │
│ Docs │ • Update docs │
│ │ • Review code │
└──────────┴──────────────────────────┘Mobile (under 1024px)
┌────────────────────────┐
│ [Search_________] [⚙️]│
├────────────────────────┤
│ Projects (5) │
│ • Project Alpha │
│ • Project Beta │
│ │
│ Tasks (12) │
│ • Update docs │
│ • Review code │
└────────────────────────┘Integration with Payload CMS
Search can query multiple Payload collections:
// Search across multiple collections
<SearchView
collections={['projects', 'tasks', 'documents']}
query={query}
>
<SearchResults />
</SearchView>Best Practices
Debounce Input
Avoid excessive queries:
const debouncedQuery = useDebounce(query, 300)
useEffect(() => {
if (debouncedQuery) {
searchAPI(debouncedQuery)
}
}, [debouncedQuery])Show Loading States
Display loading indicator while searching:
<SearchView query={query} loading={isSearching}>
{isSearching ? (
<SearchSkeleton />
) : (
<SearchResults results={results} />
)}
</SearchView>Highlight Matches
Make matching terms stand out:
// Good - highlighted matches
<SearchResult
title={<HighlightedText text={result.title} query={query} />}
/>
// Bad - no highlighting
<SearchResult title={result.title} />Show Result Counts
Help users understand scope:
<SearchView
query={query}
total={total}
title={`${total} results for "${query}"`}
/>Accessibility
Search implements accessibility features:
- ARIA labels - Descriptive search input labels
- Keyboard navigation - Navigate results with arrows
- Live regions - Announce result counts
- Focus management - Focus on results after search
<SearchView
query={query}
aria-label="Global search"
role="search"
>
<label htmlFor="search-input" className="sr-only">
Search
</label>
<input
id="search-input"
type="search"
value={query}
onChange={(e) => setQuery(e.target.value)}
aria-describedby="search-instructions"
/>
<span id="search-instructions" className="sr-only">
Type to search across all content
</span>
<div aria-live="polite" aria-atomic="true">
{results.length > 0 && (
<span className="sr-only">
{results.length} results found for {query}
</span>
)}
</div>
<div role="list">
{results.map((result) => (
<article key={result.id} role="listitem">
<a href={result.url}>{result.title}</a>
</article>
))}
</div>
</SearchView>Related Components
- Dashboard - Dashboard view
- Notifications - Notifications view
- Settings - Settings view
- Shell - App shell layout