Agent skill
tanstack-form
Use this skill when building or modifying forms with TanStack Form and Zod validation. Covers createForm, field-level validation, error handling, and mapping ProblemDetails API errors to form fields. Apply when adding new forms, implementing validation logic, or handling form submission in the Svelte frontend.
Install this agent skill to your Project
npx add-skill https://github.com/exceptionless/Exceptionless/tree/main/.agents/skills/tanstack-form
SKILL.md
TanStack Form
Documentation: tanstack.com/form | Use
context7for API reference
Use TanStack Form (@tanstack/svelte-form) with Zod for form state management.
Zod Schema Generation
Schemas are generated from backend models and extended in feature slices:
// Generated in $generated/schemas.ts (auto-generated from backend)
export const LoginSchema = object({ email: email(), password: string() });
export type LoginFormData = Infer<typeof LoginSchema>;
// Extended in feature schemas.ts
// From src/lib/features/auth/schemas.ts
import { ChangePasswordModelSchema } from "$generated/schemas";
export const ChangePasswordSchema = ChangePasswordModelSchema.extend({
confirm_password: string().min(6).max(100),
}).refine((data) => data.password === data.confirm_password, {
message: "Passwords do not match",
path: ["confirm_password"],
});
export type ChangePasswordFormData = Infer<typeof ChangePasswordSchema>;
// Re-export generated schemas
export { LoginSchema, type LoginFormData } from "$generated/schemas";
Basic Form Pattern
From src/Exceptionless.Web/ClientApp/src/routes/(auth)/login/+page.svelte:
<script lang="ts">
import { createForm } from '@tanstack/svelte-form';
import * as Field from '$comp/ui/field';
import { Input } from '$comp/ui/input';
import { Button } from '$comp/ui/button';
import { type LoginFormData, LoginSchema } from '$features/auth/schemas';
import { ariaInvalid, mapFieldErrors, problemDetailsToFormErrors } from '$shared/validation';
const form = createForm(() => ({
defaultValues: {
email: '',
password: ''
} as LoginFormData,
validators: {
onSubmit: LoginSchema,
onSubmitAsync: async ({ value }) => {
const response = await login(value.email, value.password);
if (response.ok) {
await goto('/');
return null;
}
return problemDetailsToFormErrors(response.problem);
}
}
}));
</script>
<form onsubmit={(e) => { e.preventDefault(); form.handleSubmit(); }}>
<form.Field name="email">
{#snippet children(field)}
<Field.Field data-invalid={ariaInvalid(field)}>
<Field.Label for={field.name}>Email</Field.Label>
<Input
id={field.name}
type="email"
value={field.state.value}
onblur={field.handleBlur}
oninput={(e) => field.handleChange(e.currentTarget.value)}
aria-invalid={ariaInvalid(field)}
/>
<Field.Error errors={mapFieldErrors(field.state.meta.errors)} />
</Field.Field>
{/snippet}
</form.Field>
<form.Subscribe selector={(state) => state.isSubmitting}>
{#snippet children(isSubmitting)}
<Button type="submit" disabled={isSubmitting}>
{isSubmitting ? 'Logging in...' : 'Log In'}
</Button>
{/snippet}
</form.Subscribe>
</form>
Server Error Handling
Convert ProblemDetails to form errors:
onSubmitAsync: async ({ value }) => {
const response = await login(value.email, value.password);
if (response.ok) return null;
return problemDetailsToFormErrors(response.problem);
};
Form in Dialog Pattern
Close dialog only after successful submission:
let open = $state(false);
const form = createForm(() => ({
defaultValues: { name: '' },
validators: {
onSubmit: mySchema,
onSubmitAsync: async ({ value }) => {
try {
await createMutation.mutateAsync(value);
open = false;
return null;
} catch (error: unknown) {
if (error instanceof ProblemDetails) {
return problemDetailsToFormErrors(error);
}
return { form: 'An unexpected error occurred' };
}
}
}
}));
References
See shadcn-svelte for Field component patterns.
Recommended Agent Skills
Expand your agent's capabilities with these related and highly-rated skills.
foundatio-repositories
releasenotes
Generate formatted changelogs from git history since the last release tag. Use when preparing release notes that categorize changes into breaking changes, features, fixes, and other sections.
e2e-testing
Use this skill when writing or running end-to-end browser tests with Playwright. Covers Page Object Model patterns, selector strategies (data-testid, getByRole, getByLabel), fixtures, and accessibility audits with axe-playwright. Apply when adding E2E test coverage, debugging flaky tests, or testing user flows through the browser.
tanstack-query
Use this skill when fetching data, managing server state, or handling API mutations in the Svelte frontend. Covers createQuery, createMutation, query keys, cache invalidation, optimistic updates, and WebSocket-driven refetching. Apply when adding API calls, managing loading/error states, or coordinating cache updates after mutations.
dogfood
Systematically explore and test a web application to find bugs, UX issues, and other problems. Use when asked to "dogfood", "QA", "exploratory test", "find issues", "bug hunt", "test this app/site/platform", or review the quality of a web application. Produces a structured report with full reproduction evidence -- step-by-step screenshots, repro videos, and detailed repro steps for every issue -- so findings can be handed directly to the responsible teams.
storybook
Use this skill when creating or updating Storybook stories for Svelte components. Covers Svelte CSF story format, defineMeta, argTypes, snippet-based customization, and autodocs. Apply when adding visual documentation for components, setting up story files, or running Storybook for development.
Didn't find tool you were looking for?