Handlers
Every handler returns a Response - HTML or anything else (JSON, a redirect,
204). The routing runtime is what executes a handler.
Read handler
A GET handler with html() in its args.
html()
html() adds layouts, DOCTYPE, default cache headers, and sets the status. Skip
it and a raw Response is sent as-is.
page.tsx
import type { ReadArgs } from "dashi"; export function Home({ html }: ReadArgs) { return html( <main> <h1>Hello</h1> </main>, ); }
json.ts
export function getJson(): Response { return Response.json({ ok: true }); }
Status
Pass { status } to set the status of the html() response. Default 200.
Cache
Pass { cache } to set the Cache-Control headers. CacheStrategy picks the
policy, omitted is no-store. Every sealed response sets Vary: x-slot. Public
and Immutable cannot vary on Cookie or *.
Write handler
POST, PUT, PATCH, or DELETE. Call patches() or return a raw Response.
Patches
A patch is HTML aimed at an element, by #id or /path (refresh).
update- replace the target's childrenreplace- replace the target nodeappend/prepend- add childrenbefore/after- insert siblingsremove- drop the targetrefresh- re-fetch a RouteSlot by fullsrc
add.tsx
import { patch, type WriteArgs } from "dashi"; export async function addTodo({ ctx, patches }: WriteArgs) { const title = (await ctx.req.formData()).get("title"); if (typeof title !== "string") { return patches([]); } return patches([ patch.append("#todos", <li>{title}</li>), patch.update("#count", <>3</>), ]); }
Status
Pass { status } to set the status of the patches() response. Default 200.
Forms
Form submissions are the main mechanism for patches. See Forms for more details.
ctx
req-Requestobject.url-URLobject.params- Typed params from that route. e.g.{ id: string }state- Partial app-defined state object. Mutate it in place. e.g.{ user?: MyUser }
Middleware and errors get WrapperCtx (wide params). Layouts get LayoutCtx
(state is readonly). See
Layouts, middleware, errors.