Autocomplete Suggestions
Purpose and Scope
The autocomplete suggestions example teaches a common SWR pattern: turn a user's current input into a request key, fetch matching suggestions asynchronously, and render the freshest available result without manually wiring loading, error, and cache state in every component. SWR is described by the repository as a React Hooks library for data fetching, and its core model is especially useful for input-driven interfaces because a component can keep showing known data while a newer request is being revalidated. That makes autocomplete feel responsive even when network timing varies.
Sources: README.md
The example's official documentation states its idea plainly: use SWR to fetch the suggestion for an autocomplete. In practice, that means the input value controls whether there is a valid request, the request key identifies the current query, and the fetcher returns the suggestions for that key. When the input changes, SWR treats the new key as a distinct data dependency. The component can then branch on returned values such as data, error, and loading state instead of maintaining a separate request lifecycle by hand.
Sources: README.md
This page focuses on how to reason about the example rather than on a hidden file-by-file walkthrough. The requested repository evidence includes the top-level SWR README, which defines the stale-while-revalidate behavior and the public useSWR shape, and the Next.js e2e site README, which explains the API route convention used by Next applications. Together, those sources are enough to document the system shape: a React page calls useSWR with a key and fetcher, while a local API route can serve the suggestion data under the /api namespace.
Sources: README.md, e2e/site/README.md
Relevant Source Files
- README.md - Defines SWR as a React Hooks data-fetching library, explains stale-while-revalidate behavior, and shows the primary useSWR contract with key, fetcher, data, error, and isLoading.
- e2e/site/README.md - Documents the Next.js development workflow and explains that files in pages/api are mapped to /api/* routes instead of React pages, which is the server-side shape used by examples that fetch from local API endpoints.
How to Run the Example
The official autocomplete example can be downloaded as a standalone example directory from the main repository archive. After extracting the example, install dependencies and start the development server with either Yarn or npm. These commands mirror the standard example pattern used across the repository examples and let you evaluate the autocomplete behavior in isolation from the rest of the monorepo.
curl https://codeload.github.com/vercel/swr/tar.gz/main | tar -xz --strip=2 swr-main/examples/autocomplete-suggestions
cd autocomplete-suggestions
yarn
yarn dev
# or
npm install
npm run devOnce the development server is running, open the local application in a browser and interact with the input. The important behavior to observe is not only that suggestions appear, but that the page is structured around a declarative data dependency. The UI asks for data for the current query, and SWR owns the mechanics of caching, request deduplication, loading transitions, and rerendering after the asynchronous fetcher resolves. That is the same mental model shown in the top-level quick start, just applied to a query string that changes as the user types.
Sources: README.md
If the example is implemented as a Next.js application, its suggestion endpoint can be modeled with the API route convention described by the e2e site README: files in pages/api map to /api/* and are treated as API routes rather than React pages. For an autocomplete, that route usually receives a query value, computes or looks up suggestions, and returns JSON to the browser. The SWR hook does not need to know whether that endpoint is backed by an in-memory list, a database, or a third-party service, because the fetcher abstracts the transport details.
Sources: e2e/site/README.md, README.md
Core Primitives
The first primitive is the SWR key. The README defines the key as a unique identifier of the request and notes that it is normally the URL of the API. In an autocomplete component, the URL should include the current search term, such as /api/suggest?q=react. That makes each distinct query a distinct cache entry. When the input is empty or too short, the component can avoid issuing a request by not producing a usable key, which keeps the UI from fetching meaningless suggestions.
Sources: README.md
The second primitive is the fetcher. The README describes the fetcher as an asynchronous function that accepts the key as its parameter and returns data. For autocomplete, a fetcher can be as small as a function that calls fetch on the URL and parses JSON. SWR is transport and protocol agnostic, so the fetcher could also use another HTTP client or call a typed SDK. The hook only relies on the promise resolving to data or rejecting with an error that the component can render.
Sources: README.md
The third primitive is the hook return state. The quick start shows useSWR returning data, error, and isLoading, with data initially undefined while the fetcher is pending. In an autocomplete UI, those states map cleanly to user feedback: a spinner while suggestions are loading, an error message if the endpoint fails, and a list when data is available. Because SWR rerenders the component after the fetcher completes, the input component can stay mostly declarative rather than coordinating callbacks for every network transition.
Sources: README.md
The fourth primitive is the API route boundary. The Next.js README explains that pages/api is mapped to /api/* and that files in that directory are API routes. This matters because an autocomplete example often benefits from keeping browser UI and suggestion logic close together while still using an HTTP boundary. The page component can fetch /api/suggestions with the current input value, while the route handler remains responsible for shaping the response and hiding any server-only implementation detail.
Sources: e2e/site/README.md
System-to-Code Mapping
| Concern | Repository-backed contract | Autocomplete usage |
|---|---|---|
| React data fetching | SWR is a React Hooks library for data fetching. | The input component calls useSWR from React render logic. |
| Request identity | The key uniquely identifies a request, normally as an API URL. | The key includes the current query, for example /api/suggest?q=value. |
| Async loading | data starts undefined and isLoading is true before the fetcher finishes. | The UI can show a loading indicator while suggestions are pending. |
| Error handling | useSWR returns error based on the fetcher result. | The autocomplete can show a compact failure state without losing the input. |
| Local API endpoint | pages/api maps to /api/* routes in a Next.js app. | A suggestion route can serve JSON to the SWR fetcher. |
The mapping is intentionally small because the example is built from a few composable ideas. The autocomplete component is not a special SWR API; it is a normal useSWR call whose key changes frequently. The server endpoint is not a special SWR endpoint; it is an ordinary API route reachable by URL. The power comes from letting SWR coordinate cache state and revalidation while the component stays focused on input rendering and list display.
Sources: README.md, e2e/site/README.md
Execution Flow
A typical interaction starts before the user types. The component renders with an empty input and either no suggestion key or a key that represents an empty query, depending on the example's chosen behavior. Once the user enters text, the component derives a request key from that input and passes it to useSWR with a fetcher. SWR then returns the current cache value for that key if one exists and starts or joins an asynchronous request for fresh data.
Sources: README.md
While the request is pending, the component renders the loading state. The README's quick start explains that data is undefined and isLoading is true before the request finishes. In autocomplete, this state should be lightweight: users should still be able to keep typing, and the component should not block input interaction. Because the key changes when the input changes, a later query can supersede an earlier visual state from the user's point of view, while SWR keeps cache entries organized by key.
Sources: README.md
When the API route responds, the fetcher resolves and SWR updates the hook result. The component rerenders with data populated, and the suggestion list can be rendered from that response. If the same query is entered again later, SWR's cache-first behavior means the previous suggestions can be returned quickly while revalidation checks for newer data. This is the stale-while-revalidate model from the README applied to a high-frequency user interaction rather than to a static profile page.
Sources: README.md
If the route fails or the fetcher rejects, useSWR exposes an error value. Autocomplete components should treat that as a recoverable UI condition, because the user may keep typing and produce a new key that succeeds. A compact message, empty suggestion list, or retry affordance is usually better than replacing the whole page. The README highlights built-in smart error retry as one of SWR's capabilities, but the user experience should still be designed so transient request failures do not make the input feel broken.
Sources: README.md
Implementation Pattern
A minimal autocomplete component follows the same shape as the README quick start, but derives the key from state. The fetcher receives that key, fetches JSON, and returns the parsed suggestions. The component then renders an input, a loading indicator, an error state, and the current suggestions. This skeleton omits styling and debouncing so the SWR responsibilities remain visible.
import { useState } from 'react'
import useSWR from 'swr'
const fetcher = url => fetch(url).then(res => res.json())
export default function Autocomplete() {
const [query, setQuery] = useState('')
const key = query ? `/api/suggestions?q=${encodeURIComponent(query)}` : null
const { data, error, isLoading } = useSWR(key, fetcher)
return (
<div>
<input value={query} onChange={event => setQuery(event.target.value)} />
{isLoading && <p>Loading suggestions...</p>}
{error && <p>Failed to load suggestions.</p>}
<ul>
{(data || []).map(item => <li key={item}>{item}</li>)}
</ul>
</div>
)
}The important design choice is that the key is the contract between the input and the cache. If the key includes the query, SWR can distinguish suggestions for different terms. If the key is null when the query is empty, the component can avoid unnecessary requests until there is something meaningful to search. The README's explanation that the key is the unique request identifier is the guiding rule for adapting this pattern to real applications.
Sources: README.md
On the server side, a Next.js API route can provide the JSON endpoint. The e2e site README states that the pages/api directory is mapped to /api/*, so a file such as pages/api/suggestions.js would be reachable from the browser as /api/suggestions. The route can read the query string, compute matches, and return a JSON array. SWR does not impose a response shape, but the component and fetcher must agree on whatever shape the route returns.
Sources: e2e/site/README.md, README.md
Next Steps
Use this example as a bridge from the basic useSWR quick start to more production-like search experiences. After the basic autocomplete works, consider reading the pages on keys and serialization, fetchers and data flow, cache providers, and revalidation strategies. Those topics explain how to make request identity stable, how to share fetch behavior across components, and how SWR's cache-first updates interact with focus, reconnect, and polling behavior.
Sources: README.md