# on change

> `on change { … }` is a reactive **side-effect**: the runtime re-runs it whenever a value it read changes, so it's how you keep something OUTSIDE the component in sync with something inside it — most commonly the page's title (`on change { Navigation.SetTitle(org.Name); }`). It may not write the component's own state; that's a compile error.

<!-- id: ui-on-change · area: ui · stability: stable · html: https://osysharp.com/reference/ui/on-change/ -->

## Summary        {#summary}
`on change { … }` runs a block **reactively** — the runtime re-runs it whenever a value it reads changes. Use it to
push a value from the component to somewhere **outside** it. The canonical case is a page naming its own route:

```osy syntax
component OrgEdit(string slug) {
  var org = Organization.Single(o => o.Slug == slug);

  on change { Navigation.SetTitle(org.Name); }     // the tab + browser title track the org's name
}
```

It belongs to the **`on <event>`** lifecycle-event family — `on mount` (setup, once), `on change` (a tracked reaction),
`on unmount` (teardown, once). See [on mount / on unmount](https://osysharp.com/reference/ui/lifecycle/) for the once-only siblings and [The reactivity & lifecycle model](https://osysharp.com/reference/ui/reactivity/) for the whole
execution model.

## Signature      {#signature}
```osy syntax
on change { <statements> }     // re-runs whenever a reactive value it read changes
```

`on change` takes **no name** — the `on <event>` family is anonymous. (Don't confuse it with an `onChange` **input
prop**: `Input(value: x, onChange: Handler)` is a field's change *event*, a different thing.)

## Description    {#description}

### What it's for   {#purpose}
An `on change` block is for **outward** work — a call whose result lands somewhere the component doesn't own:

| You want | Use |
|---|---|
| A computed **value** to render | `live var name = expr;` |
| Setup that runs **once**, when the page opens | `on mount { … }` ([on mount / on unmount](https://osysharp.com/reference/ui/lifecycle/)) |
| Teardown that runs **once**, when the page closes | `on unmount { … }` ([on mount / on unmount](https://osysharp.com/reference/ui/lifecycle/)) |
| To keep something **outside** the component in sync as data changes | `on change { … }` |

An `on change` body has the same powers as an `action` — it can call server functions and reach the client verbs
(`Navigation.*`, `Theme.*`). The runtime calls it for you instead of a click.

### It may not write its own state   {#no-self-write}
Assigning the component's own field from an `on change` block is a **compile error**:

> an `on change` block must not assign the component's own reactive state (`count`). That would loop: the write wakes
> the reaction, which re-runs it.

The rule holds even if the write hides behind an `action` or method the block calls — the compiler follows the call. If
you need a value, use a `live var` computed; if you need to set state once, use `on mount`; if a user gesture should set
it, use an `action`.

### When it runs   {#when}
It runs **at mount** (to establish its dependencies and do the initial sync), then **again whenever any reactive value
it read changes** — and only then. It is *dependency-tracked*: reading `org.Name` subscribes the block to `org.Name`,
so an unrelated change elsewhere on the page does not wake it. This is the whole point of the name — "on change" is
tracked-by-construction, where a block "that runs every render" would be waste. Triggers are **any** reactive read, not
only a `live var`: a plain state field reassigned by an action wakes it too. See [The reactivity & lifecycle model](https://osysharp.com/reference/ui/reactivity/).

Writing a body that is **idempotent** — safe to run again with the same inputs — is the contract; the platform
de-duplicates at the sink where it can (calling `Navigation.SetTitle` with an unchanged title does nothing).

## Examples       {#examples}
A create page whose title tracks the name **as you type** it — and falls back while the name is still blank:

```osy title="reactive-title" test app=ui-on-change
entity Organization { string Name; }

[Page("/org/new")]
[Title("New organization")]          // the static fallback (server-rendered, and before the reaction first runs)
[Render(CSR)]
component OrgCreate() {
  Organization draft;
  on mount { draft = new Organization {}; }

  live var tabName = draft?.Name ?? "New organization";
  on change { Navigation.SetTitle(tabName); }    // the tab + browser title update as you type

  render {
    Stack(gap: 4) { Input(value: draft.Name, placeholder: "Organization name"); }
  }
}
```

## See also       {#see-also}
- [component](https://osysharp.com/reference/ui/component/) — the component `on change` lives in, and its other members.
- [on mount / on unmount](https://osysharp.com/reference/ui/lifecycle/) — `on mount` / `on unmount`, for setup and teardown that run once rather than reactively.
- [The reactivity & lifecycle model](https://osysharp.com/reference/ui/reactivity/) — the execution model: declarations vs `on mount` vs `on change` vs `on unmount`, and how a change
  updates only the slots that read it.
- [Navigation](https://osysharp.com/reference/ui/navigation/) — `Navigation.SetTitle`, and the rest of the route surface an `on change` block can reach.
