# Connection

> The live state of the browser's link to the server, and the two verbs that recover it. A component you nominate as your app's connection-loss surface reads `Connection.State` to switch between "reconnecting" and "lost", shows `Connection.Attempts`, and calls `Connection.Retry()` / `Connection.Reload()` from its buttons. The platform detects the drop and mounts your surface; it renders none of the chrome.

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

## Summary        {#summary}
`Connection` is the live state of the browser's link to the server. When the server drops mid-session — it restarted,
the network went away, a deploy is rolling — the platform detects it, keeps the current page intact, and mounts the
component you nominated as your **connection-loss surface** (see [UI surfaces (app.Ui)](https://osysharp.com/reference/config/ui/)). That surface reads `Connection` to tell
the user what happened and offer a way back.

It exists so you can write that surface — a full-screen "can't reach the server" curtain, a quiet "reconnecting…" strip,
a branded card — in your own design. The platform ships a plain default overlay if you nominate none; the moment you do,
`Connection` is what your surface binds to.

`Connection` is available **only** inside your nominated connection-loss surface. An ordinary page never reads it (there
is nothing for it to say there) — reading it elsewhere is an unbound-name error.

## Signature      {#signature}
```osy syntax
Connection.State       // where the link stands right now — a ConnState (Ok / Reconnecting / Lost)
Connection.Attempts    // how many reconnect attempts have been made since the drop (an int)

Connection.Retry()     // try the server now — clears the surface if it answers
Connection.Reload()    // reload the page
```

`Connection.State` is a **`ConnState`** — a three-member enum:

| Member | Meaning |
|---|---|
| `ConnState.Ok` | The server is reachable. Your surface is unmounted, so you never render this case. |
| `ConnState.Reconnecting` | The link just dropped; the platform is retrying with backoff. A soft, transient state. |
| `ConnState.Lost` | Several retries failed — the server looks genuinely gone. Offer Retry / Reload. |

## Description    {#description}

### How a drop is detected    {#detection}
Every request the page makes reports up or down. A request that can't reach the server at all, or that comes back as a
gateway error (the server is down or restarting), flips `Connection.State` to `Reconnecting`. The platform then pings
the server on a backoff, escalating to `Lost` after a few failed tries, and returns to `Ok` the instant anything
succeeds. A normal error response — a `401`, a `404`, a `500` — is **not** a connection loss: the server answered, so
the link is fine, and your ordinary error handling still runs.

### Does my surface re-render as the state moves?   {#reactivity}
Reading `Connection` in your surface's `render` subscribes it: when the state moves `Reconnecting → Lost → Ok`, or the
attempt count climbs, the surface re-renders. A `switch` on `Connection.State` re-runs on every transition with no
polling.

### Your surface must render with the server gone   {#offline}
Your connection-loss surface has to render **with the server gone**, so the platform fetches it up front — while the
link is still alive — and holds it ready. That puts one real constraint on the component: it must be **self-contained**.
Build it from the [component](https://osysharp.com/reference/ui/component/) built-in elements only — no child components to fetch, no data to load — because
anything it would fetch when it mounts is exactly what's unreachable. It renders from `Connection` and nothing else.

### Retrying by hand — `Connection.Retry()`   {#recovering}
`Connection.Retry()` pings the server immediately — the button a user presses when they think the network is back. If
the server answers, the surface clears itself; if not, the state stays `Lost` and the backoff continues.
`Connection.Reload()` reloads the page outright — the heavier reset for when a retry isn't enough.

Neither is required: a surface can simply say "reconnecting…" and let the automatic backoff recover on its own. The
verbs are there for the `Lost` case, where the user wants a button.

### Can I name something `Connection`? — shadowing   {#shadowing}
`Connection` is an ambient name, not a keyword. A parameter or state member named `Connection` shadows it, exactly as a
local variable shadows any other ambient. Nothing is reserved.

## Examples       {#examples}

### A connection-loss surface    {#example-surface}
One component covers both states — a quiet strip while reconnecting, a blocking card once lost. Nominate it with
[UI surfaces (app.Ui)](https://osysharp.com/reference/config/ui/) (`app.Ui = new AppUi { ConnectionSurface = OfflineOverlay };`).

```osy title="a connection-loss surface" test app=ui-connection
// The tokens this overlay draws with. They are YOUR app's — the platform declares none of them — so a copy of this
// example needs a theme that names them (or your own names substituted throughout).
theme App {
  Colors {
    Surface0 = "#FFFFFF"; Surface1 = "#F7F8FA";
    Border = "#E3E6EA"; BorderStrong = "#C7CCD3";
    FillAccent = "#0077B6"; OnAccent = "#FFFFFF"; TextMuted = "#6B7280";
  }
  Radius { Card = "12px"; Control = "8px"; }
  FontWeight { Medium = 500; }
}

[AllowAnonymous]
component OfflineOverlay() {
  action Retry()  { Connection.Retry(); }
  action Reload() { Connection.Reload(); }

  render {
    if (Connection.State == ConnState.Lost) {
      // A full-screen curtain: the server looks gone, so block the dead view and offer a way back.
      Row(align: Align.Center, justify: Justify.Center, position: Position.Fixed, inset: 0, bg: Colors.Surface0) {
        Box(bg: Colors.Surface1, border: Colors.Border, borderW: 1, rounded: Radius.Card, p: 5, maxW: "400px") {
          Stack(gap: 3, align: Align.Center) {
            Text("Can't reach the server", fontWeight: FontWeight.Medium);
            Text("Your connection dropped. Retry, or reload the page.", color: Colors.TextMuted, textAlign: TextAlign.Center);
            Row(gap: 2, w: "100%") {
              Pressable(onClick: Retry,  grow: 1) { Row(align: Align.Center, justify: Justify.Center, h: "40px", bg: Colors.FillAccent, color: Colors.OnAccent, rounded: Radius.Control) { Text("Retry"); } }
              Pressable(onClick: Reload, grow: 1) { Row(align: Align.Center, justify: Justify.Center, h: "40px", borderW: 1, border: Colors.BorderStrong, rounded: Radius.Control) { Text("Reload"); } }
            }
          }
        }
      }
    } else if (Connection.State == ConnState.Reconnecting) {
      // A quiet, non-blocking top strip — a transient blip should not lock the UI.
      Row(align: Align.Center, justify: Justify.Center, position: Position.Fixed, top: 0, left: 0, right: 0, py: 2, bg: Colors.Surface1, borderBW: 1, border: Colors.Border) {
        Text("Reconnecting…", fontWeight: FontWeight.Medium);
      }
    }
  }
}
```

### Showing the attempt count    {#example-attempts}
```osy syntax
Text("Reconnecting… (attempt " + Connection.Attempts + ")");
```

## See also       {#see-also}
- [UI surfaces (app.Ui)](https://osysharp.com/reference/config/ui/) — `app.Ui`, where you nominate the component `Connection` binds to.
- [component](https://osysharp.com/reference/ui/component/) — components, `render` blocks, actions, and the built-in elements a surface is built from.
- [routes and pages](https://osysharp.com/reference/ui/routing/) — how a failed navigation rolls back and leaves the current page intact underneath the surface.
