# Search button

> A query that runs when the search button is pressed, keeps the previous results and refetches like any query afterwards.

Page: https://svelte-lean.vercel.app/query/recipes/search-button · Markdown: https://svelte-lean.vercel.app/query/recipes/search-button.md · Index: https://svelte-lean.vercel.app/llms.txt

A query that runs when the form is submitted, not on every keystroke. After the first search it is an ordinary query: cached, refetched, polled.

## Example

Search for a name, then search for another one and watch the previous results stay.

```svelte
<!-- src/routes/members/search/+page.svelte -->
<script lang="ts">
	import { createQuery } from '@svelte-lean/query';
	import { listMembers } from '$api/members';

	// Nothing is requested until load(); afterwards it shows that search (cached, refetch).
	const results = createQuery(listMembers, { when: false, keepPrevious: true });
	let term = $state('');
	let searched = $state(false);

	function submit(event: SubmitEvent) {
		event.preventDefault();
		// load() resolves with the data; a failure is also written to results.error.
		searched = true;
		results.load({ search: term }).catch(() => {});
	}
</script>

<form role="search" aria-label="Search members" onsubmit={submit}>
	<input type="search" aria-label="Name" bind:value={term} />
	<button disabled={results.loading}>Search</button>
</form>

{#if !searched}
	<p>Enter a name and press Search.</p>
{:else if results.error}
	<p role="alert">{results.error.message}</p>
{:else if results.data}
	<p>{results.data.total} found{results.info.placeholder ? ', updating' : ''}</p>
	<ul>
		{#each results.data.rows as member (member.id)}
			<li>{member.name}</li>
		{/each}
	</ul>
{/if}
```

The component shown, against an in-memory server that answers after a fixed delay.

## How it works

| Moment | Request | State |
| --- | --- | --- |
| Before the first submit | none | `blocked: 'when'` |
| Typing | none: the params come from `load()`, not from state | unchanged |
| Submit | `GET api/members?search=…`, cause `user` | `loading` |
| Submit another term | a new key; the previous request is aborted | `loading`, previous rows shown, `info.placeholder: true` |
| Submit a term searched before | a refetch of the cached key | cached rows at once |

- `{ when: false }` pauses automatic fetching; `load(params)` pins the params and fetches, always with a request.
- A native `<form role="search">` gives Enter to submit and a search landmark.
- `load()` resolves with the data and rejects on failure; the same error is in `results.error` for the template.

## Variations

### Run the last search again

```ts
// Run the last search again (cause `user`: it shows `loading`).
const again = () => results.refetch();
```

### Follow invalidations after the first search

```ts
// A search that should also follow invalidations after its first start holds its params in
// state and returns undefined until they exist.
let submitted = $state<string | undefined>();
const live = createQuery(listMembers, () =>
	submitted === undefined ? undefined : { search: submitted }
);
const clear = () => {
	term = '';
	submitted = undefined; // back to "nothing searched yet"; the cache keeps the results
};
```

## Related

- [Reading](https://svelte-lean.vercel.app/query/reading.md): `load()` next to `when` and a missing input.
- [Filtered table](https://svelte-lean.vercel.app/query/recipes/filtered-table.md): filters that apply as you type.
