Type-safe form validation for SvelteKit Remote Functions using Standard Schema compatible validators.
- 🎯 Works with any Standard Schema compatible library (Zod, Valibot, Arktype, etc.)
- 🔒 Full type safety with automatic type inference
- ⚡ Preserves all SvelteKit form features (progressive enhancement,
enhance,buttonProps, etc.) - 📦 Lightweight with zero dependencies (besides your validator)
- 🎭 Same API as SvelteKit's
formfunction
npm install formshape
# or
pnpm add formshape// src/routes/contact/data.remote.tsimport{z}from'zod'import{form}from'$app/server'import{createValidated}from'formshape'// Create the validated function using your app's form functionconstvalidated=createValidated(form)// Define your schemaconstcontactSchema=z.object({name: z.string().min(2,'Name must be at least 2 characters'),email: z.string().email('Invalid email address'),message: z.string().min(10,'Message must be at least 10 characters')})// Create your form handler - data is fully typed!exportconstsubmitContact=validated(contactSchema,async(data)=>{// data is typed as { name: string; email: string; message: string }awaitsendEmail(data)return{success: true,message: 'Thank you for your message!'}})<scriptlang="ts">import { submitContact } from'./data.remote.js'</script>
<form {...submitContact}>
<inputname="name" />
{#ifsubmitContact.result&&'errors'insubmitContact.result}
<span>{submitContact.result.errors.name?.join(', ')}</span>
{/if}
<inputname="email"type="email" />
{#ifsubmitContact.result&&'errors'insubmitContact.result}
<span>{submitContact.result.errors.email?.join(', ')}</span>
{/if}
<textareaname="message"></textarea>
{#ifsubmitContact.result&&'errors'insubmitContact.result}
<span>{submitContact.result.errors.message?.join(', ')}</span>
{/if}
<button>Send Message</button>
</form>
{#ifsubmitContact.result?.success===true}
<p>{submitContact.result.message}</p>
{/if}The createValidated function takes your app's form function and returns a validated function. This approach ensures that the package works correctly when installed from npm, as it uses your app's SvelteKit context rather than trying to import from $app/server directly.
When validation fails, the function returns:
{success: false,errors: Record<string,string[]>,data: unknown// The original form data}When validation succeeds, your handler is called with the validated data and its return value is passed through.
The validated form maintains full compatibility with SvelteKit's enhance:
<form
{...submitContact.enhance(async ({ submit }) => {
const result =awaitsubmit()
// Handle the result
})}
>
<!-- form fields -->
</form>Any Standard Schema compatible validator works:
import*asvfrom'valibot'constschema=v.object({email: v.pipe(v.string(),v.email())})exportconstmyForm=validated(schema,async(data)=>{// ...})import{type}from'arktype'constschema=type({email: 'email',age: 'number > 0'})exportconstmyForm=validated(schema,async(data)=>{// ...})Creates a validated function using your app's form function.
- Parameters:
form: The form function from$app/server
- Returns: A
validatedfunction
Creates a form handler with validation.
- Parameters:
schema: A Standard Schema compatible validatorhandler: An async function that receives validated data
- Returns: A
RemoteFormobject (same as SvelteKit'sform)
MIT