Form
Build progressive forms with submit, validate, enhance, and field errors.
Use Form when the browser should submit user input with normal form semantics while your server handler stays inside Effect. It is the best fit for validation, field errors, and progressive enhancement.
When to use this
Use forms for sign in, profile editing, settings, creation flows, and anything that should still have a clear HTML shape. Use Command for non-form mutations.
Minimal working example
import { Form } from "svelte-effect-runtime/server";
import { Effect, Schema } from "effect";
const ProfileInput = Schema.Struct({
name: Schema.String,
});
export const update_name = Form(
ProfileInput,
({ data }) =>
Effect.succeed({ name: data.name }),
);<script lang="ts">
import { update_name } from "./profile.remote";
</script>
<form {...update_name}>
<input name="name" />
<button>Save</button>
</form>Realistic variant
Validate before committing the mutation:
import { Form } from "svelte-effect-runtime/server";
import { Effect, Schema } from "effect";
const ProfileInput = Schema.Struct({
name: Schema.String,
});
export const update_name = Form(
ProfileInput,
({ data, invalid }) =>
Effect.gen(function* () {
if (data.name.trim().length === 0) {
return yield* invalid.name("Name is required");
}
return { name: data.name.trim() };
}),
);On the client, the generated form object keeps SvelteKit's form descriptors. Programmatic helpers such as validate, submit, and enhance are wrapped so they can be yielded from Effect-aware code.
Common mistakes
- Using a command for complex form validation and then rebuilding form behavior manually.
- Trusting client-side validation without validating again in the server handler.
- Returning one generic message when users need field-specific errors.
- Forgetting that
enhanceis progressive; the server handler should still be correct without JavaScript.