Skip to content

Getting Started

Install Astro Utils Forms and run a complete server action without an external service.

View Markdown

Build a form that sends a name to your server and renders a greeting. Start inside an existing Astro project; no database or email provider is needed.

npm install @astro-utils/forms @astrojs/node
astro.config.mjs
import { defineConfig } from 'astro/config';
import node from '@astrojs/node';
import forms from '@astro-utils/forms/dist/integration.js';
export default defineConfig({
output: 'server',
adapter: node({ mode: 'standalone' }),
integrations: [forms]
});
src/middleware.ts
import forms from '@astro-utils/forms';
export const onRequest = forms();

The default is enough for local development. For deployed projects, pass a stable environment secret through the middleware configuration. Keep it stable across restarts and out of source control. For an existing middleware chain, compose this middleware with Astro’s sequence() helper.

Use one WebForms root around your form content. The examples throughout these docs import this layout.

src/layouts/Layout.astro
---
import { WebForms } from '@astro-utils/forms/forms.js';
---
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width" />
<title><slot name="title" /></title>
</head>
<body>
<WebForms>
<slot />
</WebForms>
</body>
</html>

Save the following page as src/pages/hello.astro. Preview simulates the same interaction inside the docs; running the page in your own project executes the callback on your server.

---
import { BButton, BInput, Bind, BindForm, FormErrors } from '@astro-utils/forms/forms.js';
import Layout from '../layouts/Layout.astro';
const bind = Bind({ name: '' });
let message = '';
function greet() {
message = `Hello, ${bind.name}! Your server action ran.`;
}
---
<Layout>
<span slot="title">Your first form</span>
<BindForm {bind}>
<FormErrors />
<label for="name">Your name</label>
<BInput id="name" name="name" required maxlength={40} />
<BButton onClick={greet} whenFormOK>Say hello</BButton>
{message && <p role="status">{message}</p>}
</BindForm>
</Layout>

Start your Astro project with your package manager’s dev script. Open /hello on the URL printed by Astro, enter a name, and select Say hello. You should see Hello, Alex! Your server action ran. when you enter Alex. An empty name prevents the valid-only callback.

  1. WebForms receives the POST request.
  2. BindForm restores state and validates the submitted controls.
  3. BButton calls greet when validation succeeds.
  4. The form renders again with the updated message.

message is request-local feedback. Use omitState when feedback is stored on bind but should not persist into the next submission.

Learn binding and validation, or adapt the account example to your application. If the action does not run, check server rendering, middleware, the integration, and the WebForms layout first.