## Demo: form-cancel ### FormCancel.svelte ```svelte

The action sleeps 3 s to simulate a slow lookup. Each variant below uses the same action but cancels at a different point — or not at all.

cancel() — pre-flight short-circuit

The submit callback receives cancel. Calling it skips the fetch entirely — no request is sent, no result callback runs. Use this for client-side validation or any condition you can check before leaving the browser.

controller.abort() — in-flight cancellation

The submit callback also receives an AbortController. Calling controller.abort() stops a fetch that has already started. Here a 1.5 s timeout aborts the 3 s lookup; enhance swallows the AbortError and resets the form to idle.

Plain HTML — no enhance

Without JavaScript there is nothing to cancel. The browser POSTs and waits the full 3 s, then the page re-renders with the result.

``` ### CancelDemo.svelte ```svelte

{label}

{#if result}

{result}

{/if} {#if message} {/if}
``` ### AbortDemo.svelte ```svelte

{label}

{#if result}

{result}

{/if} {#if message} {/if}
``` ### PlainDemo.svelte ```svelte

{label}

{#if initialResult}

{initialResult}

{/if} {#if initialMessage} {/if}
``` ### routes.ts ```ts import { Mochi, fail, success } from 'mochi-framework'; import type { MochiRouteValue } from 'mochi-framework'; export const routes: Record = { '/demos/form-cancel': Mochi.page('./src/demos/form-cancel/FormCancel.svelte', { actions: { lookup: async ({ formData }) => { const query = String(formData.get('query') ?? '').trim(); if (!query) { return fail(400, { error: 'Query is required' }); } await Bun.sleep(3000); return success({ result: `Found: ${query} — status active` }); }, }, }), }; ``` ### index.ts ```ts import { Mochi, logger } from 'mochi-framework'; await Mochi.serve({ port: 3333, development: process.env.MODE === 'development', routes: { '/': Mochi.page('./src/Home.svelte'), }, }); logger.info('Server running at http://localhost:3333'); ```