Autocomplete latency above 300ms breaks the perceptual contract users have with search — they stop trusting the suggestions and abandon the feature entirely. ISO 25010:2011 performance-efficiency frames this as a functional responsiveness requirement, not a nice-to-have. Directories that serve irrelevant or hardcoded suggestions compound the damage: users waste time selecting a suggestion that returns no matching listings, eroding confidence in the product. On mobile networks, where the autocomplete round-trip competes with elevated latency, a bloated debounce delay also hammers your backend with redundant queries on every keystroke, driving up infrastructure cost.
High because autocomplete latency above 300ms measurably degrades engagement and causes users to abandon search before submitting a query.
Add a debounced fetch in components/SearchInput.tsx capped at 300ms, querying your real listing index — not a static category list.
// components/SearchInput.tsx
useEffect(() => {
if (!query) return setSuggestions([])
const timer = setTimeout(async () => {
const res = await fetch(`/api/listings/search?q=${encodeURIComponent(query)}`)
const data = await res.json()
setSuggestions(data.results.slice(0, 5))
}, 250) // ≤300ms
return () => clearTimeout(timer)
}, [query])
Index the name and category columns in your listings table so the /api/listings/search handler returns in single-digit milliseconds under load.
ID: directory-search-discovery.search-input.autocomplete-speed
Severity: high
What to look for: Enumerate all relevant files and Examine the autocomplete/suggestions implementation. Look for debouncing logic (e.g., debounce, useDeferredValue, or custom delay) and the API call that fetches suggestions. Measure the delay from keystroke to suggestions appearing in the UI. If debouncing is used, check the debounce delay (should be ≤300ms). If autocomplete fetches from an API, check whether the query is reasonable (not searching the entire table on every keystroke). Verify that suggestions are actual listing data (names, categories, or other relevant fields from the directory), not generic placeholder text. Quote the exact code pattern or configuration value found.
Pass criteria: At least 1 implementation must be present. Suggestions appear within 300ms of the user's last keystroke. Results are sourced from actual listing data in the directory (not hardcoded examples or unrelated data). Debounce delay (if used) is ≤300ms, and the implementation does not cause unnecessary API calls.
Fail criteria: Suggestions take longer than 300ms to appear, or suggestions are generic/irrelevant (e.g., showing unrelated categories or not reflecting the user's query at all), or debounce delay is >300ms. A partial or incomplete implementation does not count as pass.
Skip (N/A) when: The directory has no autocomplete feature at all. Signal: no autocomplete or suggestions component found.
Cross-reference: For performance analysis of search API response times, the Performance & Load audit covers server response optimization.
Detail on fail: Describe the timing and relevance issue. Example: "Autocomplete has a 500ms debounce delay. Suggestions appear 500+ ms after typing. Suggestions are hardcoded category names, not search results from actual listings." or "Suggestions appear in 150ms but show unrelated or random listing names."
Remediation: Set up debounced search with a 200-300ms delay and fetch suggestions from your backend listing API:
// components/SearchInput.tsx
import { useEffect, useState } from 'react'
export function SearchInput() {
const [query, setQuery] = useState('')
const [suggestions, setSuggestions] = useState([])
useEffect(() => {
if (!query) return setSuggestions([])
const timer = setTimeout(async () => {
const res = await fetch(`/api/listings/search?q=${encodeURIComponent(query)}`)
const data = await res.json()
setSuggestions(data.results.slice(0, 5)) // top 5
}, 300)
return () => clearTimeout(timer)
}, [query])
return (
<div>
<input
type="text"
value={query}
onChange={e => setQuery(e.target.value)}
placeholder="Search listings..."
/>
{suggestions.length > 0 && (
<ul>
{suggestions.map(item => (
<li key={item.id}>{item.name}</li>
))}
</ul>
)}
</div>
)
}
Ensure your /api/listings/search endpoint is optimized to return results quickly (use database indexes on searchable fields like name and category).