# @svelte-lean/query/forms

> fieldErrors(), issues() and errorKey(): server errors into native form state and stable message keys.

Page: https://svelte-lean.vercel.app/query/api/forms · Markdown: https://svelte-lean.vercel.app/query/api/forms.md · Index: https://svelte-lean.vercel.app/llms.txt

Server errors into native form state: an attachment that writes aria-invalid, aria-describedby, custom validity and focus, and removes exactly what it wrote.

## Import

`import`

```ts
import { fieldErrors, issues, errorKey } from '@svelte-lean/query/forms';
```

## Usage

`invite.svelte`

```svelte
<script lang="ts">
	import { createMutation } from '@svelte-lean/query';
	import { fieldErrors, issues } from '@svelte-lean/query/forms';
	import { createMember } from '$api/members';

	const save = createMutation(createMember);

	function submit(event: SubmitEvent & { currentTarget: HTMLFormElement }) {
		event.preventDefault();
		const data = new FormData(event.currentTarget);
		save.run({
			name: String(data.get('name')),
			email: String(data.get('email')),
			team: 'Design',
			role: 'member'
		});
	}
</script>

<!-- The server's 422 marks the fields: aria-invalid, aria-describedby, custom validity, focus. -->
<form {@attach fieldErrors(() => save.error)} onsubmit={submit}>
	<label>Name <input name="name" required /></label>
	{#each issues(save.error, 'name') as message (message)}<p>{message}</p>{/each}
	<label>Email <input name="email" type="email" required /></label>
	{#each issues(save.error, 'email') as message (message)}<p>{message}</p>{/each}
	<button disabled={save.busy}>Invite</button>
</form>
```

## Size

Production Vite builds of a small consumer entry, Svelte external. A marginal row is the bytes the entry adds over the row it names.

| Build | Over | gzip | brotli | Budget (gzip) |
| --- | --- | --- | --- | --- |
| `forms (marginal)` | `query+mutation` | 1406 B | 1226 B | 1600 B |

Read from `packages/query/artifacts/size.json`. Every entry and its method: [Performance](https://svelte-lean.vercel.app/query/performance.md).

## Functions

The attachment and two readers of an error.

### Exports

Runtime exports of the entry.

| Name | Type | Default | Description |
| --- | --- | --- | --- |
| # `fieldErrors` | `(source: () => QueryError \| FailureResult \| undefined, options?: FieldErrorsOptions) => FormAttachment` | – | {@attach fieldErrors(() =\> save.error)} on a form: marks the controls the error names; re-runs when the error changes. |
| # `issues` | `(source, path?: string) => FieldIssue[] \| string[]` | – | Every issue, or the messages of one path (the exact key, then its wildcard form 'lines.\*.sku'). |
| # `errorKey` | `(error: QueryError) => ErrorKey` | – | A stable, untranslated key for i18n. |

## Options

FieldErrorsOptions, the second argument of fieldErrors().

### FieldErrorsOptions

All optional.

| Name | Type | Default | Description |
| --- | --- | --- | --- |
| # `name` | `(path: string) => string` | `the dot path, the bracket form, then name[]` | Server path to control name. |
| # `focus` | `boolean` | `true` | Focus the first invalid control; never taken from a control being typed in. |
| # `validity` | `boolean` | `true` | setCustomValidity(first message) on each marked control. |
| # `text` | `(message, path) => string` | `identity` | Translate a field message. |
| # `unmatched` | `(issues: FieldIssue[]) => void` | – | Issues with no control in this form, to render elsewhere. |

### FieldIssue

One message of issues().

| Name | Type | Default | Description |
| --- | --- | --- | --- |
| # `path` | `string` | – | Dot form: 'lines.0.sku'. |
| # `message` | `string` | – | The message. |

### ErrorKey

What errorKey() returns: the kind, with HTTP statuses split.

| Name | Type | Default | Description |
| --- | --- | --- | --- |
| # `network` | `ErrorKey` | – | No answer. |
| # `timeout` | `ErrorKey` | – | The attempt timed out. |
| # `server` | `ErrorKey` | – | HTTP 5xx. |
| # `rate-limited` | `ErrorKey` | – | HTTP 429. |
| # `not-found` | `ErrorKey` | – | HTTP 404. |
| # `conflict` | `ErrorKey` | – | HTTP 409. |
| # `http` | `ErrorKey` | – | Any other HTTP status. |
| # `forbidden` | `ErrorKey` | – | 401 or 403, or a refusal classified as forbidden. |
| # `validation` | `ErrorKey` | – | A 422 or a refusal with field errors. |
| # `refused` | `ErrorKey` | – | An application refusal (success: false). |
| # `parse` | `ErrorKey` | – | The answer did not match its schema. |

## Guide

How to use it, with examples: [Forms](https://svelte-lean.vercel.app/query/forms.md). All entry points: [Svelte Lean Query](https://svelte-lean.vercel.app/query.md).
