# Log in with feedback

Success, error feedback, and session updates.

Source: https://withastro-utils.github.io/docs/examples/login/

Complete the [Forms setup](https://withastro-utils.github.io/docs/guides/forms/getting-started/index.md) first, or use the configuration, middleware, and layout files in the sidebar. Install `@astro-utils/forms` and `@astrojs/node` in an existing Astro project.

## Try the interaction

Use **demo@example.com** and **demo-only** for success. Any other credentials show an error. Try an error followed by success to see feedback reset.

### src/layouts/Layout.astro

```astro title="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>
```

### src/pages/login.astro

```astro title="src/pages/login.astro"
---
import { BButton, BInput, Bind, BindForm, FormErrors } from '@astro-utils/forms/forms.js';
import Layout from '../layouts/Layout.astro';

const bind = Bind({ email: '', password: '' });

let error = '';
let message = '';

function logIn() {
    if (bind.email !== 'demo@example.com' || bind.password !== 'demo-only') {
        error = 'Email or password is incorrect.';
    } else {
        Astro.locals.session.demoUserId = 'demo-user';
        message = 'Signed in to the demo.';
    }
}
---
<Layout>
    <span slot="title">Log in with feedback</span>
    <BindForm {bind} omitState={['password']}>
        <FormErrors />

        {error && <p role="alert">{error}</p>}
        {message && <p role="status">{message}</p>}

        <label for="email">Email</label>
        <BInput id="email" name="email" type="email" autocomplete="email" required />

        <label for="password">Password</label>
        <BInput id="password" name="password" type="password" autocomplete="current-password" required />

        <BButton onClick={logIn} whenFormOK>Log in</BButton>
    </BindForm>
</Layout>
```

### src/middleware.ts

```ts title="src/middleware.ts"
import forms from '@astro-utils/forms';

export const onRequest = forms();
```

### astro.config.mjs

```js title="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]
});
```

## How it works

These public credentials demonstrate the form flow only. Replace the demo condition with your authentication provider before using this in an application. Passwords are excluded from view state; the callback clears the submitted value. Only the demo user ID is saved in the session.

## Continue

Read the [session reference](https://withastro-utils.github.io/docs/reference/forms/session/index.md).
