---
title: Live views
description: Server-rendered views whose state stays on the server; the browser sends events and gets back only what changed.
section: Frontend
order: 6
---

# Live views

<p class="lead">A live view keeps its state on the server and renders it there. The browser sends user events and gets back only the values that changed, often a few bytes.</p>

Use it when the server should own the state: a register, a dashboard, a checkout. It isn't meant for collaborative editing: two people typing in the same field overwrite each other, last write wins.

## A view

A view is `views/<name>.js` in the app:

```js title="views/counter.js"
export const rule = "@request.auth.id != null";

export function mount(ctx) {
  return { count: 0 };
}

export function render(state, html) {
  return html`<button sluurp-click="bump">Clicked ${state.count} times</button>`;
}

export function handle(event, payload, state, ctx) {
  if (event === "bump") return { ...state, count: state.count + 1 };
  return state;
}
```

- `rule`: who may open it, in the [rules language](/docs/rules).
- `mount`: returns the initial state; `ctx` has the user who opened the view.
- `render`: renders the state with the `html` tag.
- `handle`: takes an event and returns the next state.

## On the page

```ts title="app.ts"
import { mount } from "sluurp/live";
await mount("#counter", "counter");
```

Attributes bind DOM events to view events:

```html title="HTML"
<button sluurp-click="bump">+1</button>
<input sluurp-input="search" name="q">
<form sluurp-submit="save">…</form>
```

The payload includes the element's value, a form's fields, and any `sluurp-value-*` attributes. Add `sluurp-ignore` to an element to leave its children untouched across updates, e.g. for a client-side widget.

## Why so little goes over the wire

A tagged `html` template is already split by JavaScript into static strings and dynamic values. Only the values are diffed between renders, and only changed ones are sent. A counter going from 41 to 42 sends `42`.

Auth is the regular [browser client's](/docs/client), so a view sees the same user the REST API does.
