# 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); }`) — or to refetch when a value changes (`on change { results = Search(query); }`). It may write a field of its own that it does not read; writing one it reads would loop, and is 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 { … }` |
| To fetch again whenever a value it depends on changes | `on change { results = Search(query); }` |

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 write a field it does not read   {#no-self-write}
The block re-runs whenever a value it READ changes, so the fields it writes are its OUTPUT and the ones it reads are
its INPUT. Writing an output is how "fetch again when this changes" is spelled — `query` is read, `names` is written,
and typing into the box is what refetches:

```osy title="refetch when the query changes" test app=ui-on-change-refetch
entity Comet { string Name; }

[AllowAnonymous]
List<string> NamesLike(string q) => Comet.Where(c => c.Name.Contains(q)).Select(c => c.Name).ToList();

[Route("/comets")] [AllowAnonymous] [Render(CSR)]
component CometSearch() {
  string query = "";
  List<string> names = [];
  on change { names = NamesLike(query); }
  render {
    Stack(gap: 2) {
      Input(value: query, label: "Search");
      foreach (var n in names) { Text(n); }
    }
  }
}
```

Writing a field the block also READS is a **compile error**, because the write would wake the block again:

> an `on change` block must not write `count` and also read it. That would loop: the reaction re-runs whenever a value
> it READ changes, so writing one wakes it again.

The rule follows the reads and writes behind an `action` or method the block calls, and the reads behind a `live var`
it reads; `n++` both reads and writes, so it is always refused. 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; }

[Route("/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.
