---
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 what the person did and gets back only the values that changed, often a few bytes.</p>

It suits anything where the server should hold the truth: a register, a dashboard, a checkout. It isn't for collaborative editing: two people typing in one field overwrite each other, in the order they arrive.

## 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` says who may open it, in the [rules language](/docs/rules).
- `mount` makes the first state; `ctx` says who opened the view.
- `render` draws 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");
```

Elements say which events they send:

```html title="HTML"
<button sluurp-click="bump">+1</button>
<input sluurp-input="search" name="q">
<form sluurp-submit="save">…</form>
```

The payload carries the element's value, a form's fields, and any `sluurp-value-*` attributes. `sluurp-ignore` on an element keeps its children as they are across updates, for a component the browser owns.

## Why so little goes over the wire

An `html` template is split by JavaScript itself into the parts that never change and the values put into them. Only the values are compared between renders, and only those that differ are sent. A counter going from 41 to 42 sends `42`.

Signing in is the ordinary [browser client's](/docs/client), so a view sees the same person the REST API does.
