Osy#the first language built for agents
Agents firstAgentic appsWorkflowsDurable Execution — built inSecurityTestingThe editorThe UI modelOne program

Reference / Config

UI surfaces (app.Ui)

app.Ui = new AppUi { ConnectionSurface = …, NotFoundSurface = …, ForbiddenSurface = …, ErrorSurface = …, PendingIndicator = …, PendingDelayMs = …, PendingMinShowMs = … };

`app.Ui` nominates the app's own components for the "system surfaces" the platform would otherwise render a bare fallback for — the connection-loss overlay, the not-found (404) page, the forbidden (403) page, and the error page — and tunes the automatic busy indicator. A singleton; the `Ui` block groups these so more can be added without a new setting each time.

preview1 example compiled by CIconfiguiconnection

Summary#

app.Ui is where you hand the platform your own components for the system surfaces it would otherwise draw a bare fallback for — the "something happened, here's the app's branded page" moments. It is a singleton — one UI configuration per app — and it groups these overrides under one Ui block, so an app opts into each surface it wants to own and inherits the platform default for the rest.

app.Ui = new AppUi {
  ConnectionSurface = OfflineOverlay,   // shown when the server drops mid-session
  NotFoundSurface   = NotFoundPage,     // shown (HTTP 404) when no route matches the address
  ForbiddenSurface  = ForbiddenPage,    // shown when a signed-in user is refused a page (403)
  ErrorSurface      = ErrorPage,        // shown when a page fails to load unexpectedly
};

Signature#

app.Ui = new AppUi {
  ConnectionSurface = OfflineOverlay,   // the connection-loss overlay
  NotFoundSurface   = NotFoundPage,     // the not-found (404) page
  ForbiddenSurface  = ForbiddenPage,    // the forbidden (403) page
  ErrorSurface      = ErrorPage,        // the error page
};

app.Ui is a single value, not a list. Each member names a component by name — the same name you gave it in its component X { … } declaration.

Description#

An AppUi has these members (each optional — omit one, or omit app.Ui entirely, to keep the platform default):

  • ConnectionSurface — the component the platform mounts, as a fixed overlay over the current page, when the browser loses its link to the server. It reads the Connection ambient (Connection.State, Connection.Attempts) and calls Connection.Retry() / Connection.Reload(). Because it has to render with the server gone, it must be self-contained — built from the component built-in elements, with no child components to fetch and no data to load. See Connection for the full surface and its constraints.
  • NotFoundSurface — the page the platform serves, with HTTP status 404, when a visitor hits an address the app doesn't route. The server sends your app's shell with this component as the page (so the 404 keeps the correct status for crawlers and monitoring, but the body is your branded page instead of plain text) and the client renders it. Unlike the connection surface, a 404 means the server answered, so this page may use anything the app has. Mark it [AllowAnonymous] so a bad URL renders it for anyone rather than bouncing a signed-out visitor to login.
  • ForbiddenSurface — the page shown when a signed-in user is refused a page they aren't permitted to see (a 403). The platform mounts it in place of the built-in access-denied surface.
  • ErrorSurface — the page shown when a page fails to load for an unexpected reason, in place of the built-in "couldn't load" surface.

Three more members tune the busy indicator — the automatic spinner the platform shows while an action is in flight (see Pending for the full surface, including the Pending ambient):

  • PendingIndicator — your own component for the global busy affordance, in place of the built-in top progress bar.
  • PendingDelayMs — how long an action must run before the indicator appears (so an instant action never flashes one); 0 uses the platform default.
  • PendingMinShowMs — once shown, the minimum time the indicator stays up, so it can't blink off; 0 uses the default.

The forbidden and error surfaces render at boot-failure time — a refusal or a failure that can happen before the app has a working session, or while the server is unreliable. So the platform inlines their trees into the page up front, and the client renders them with no further request. That is what makes them work when nothing else does — and it puts the same constraint on them as the connection surface: they must be self-contained, built from the component built-in elements (with [Composable] children bundled), carrying no data. Offer a way out with plain Links (sign in as a different account, go home). Mark each [AllowAnonymous].

Each nominated component must exist, and none is a routed page — the platform serves or mounts each by name for its occasion, so none needs a [Page("…")].

app.Ui is a singleton: an app declares it once. Removing a member reverts that surface to the platform default.

Sign-in is deliberately not part of this block — it is a real flow, declared via app.AuthBootstrap { LoginPage = … }, not a passive surface.

Examples#

Declare the surfaces, then nominate them:

[AllowAnonymous]
component OfflineOverlay() {
  action Retry() { Connection.Retry(); }
  render {
    if (Connection.State == ConnState.Lost) {
      Row(align: Align.Center, justify: Justify.Center, position: Position.Fixed, inset: 0, bg: "#1a1a1a") {
        Text("Can't reach the server");
      }
    }
  }
}

[AllowAnonymous]
component NotFoundPage() {
  render {
    Row(align: Align.Center, justify: Justify.Center, minH: "100vh", bg: Colors.Surface) {
      Stack(gap: 3, align: Align.Center) {
        Text("Page not found");
        Link(href: "/") { Text("Go home"); }
      }
    }
  }
}

app.Ui = new AppUi {
  ConnectionSurface = OfflineOverlay,
  NotFoundSurface   = NotFoundPage,
};

See also#

  • Connection — the Connection ambient the connection surface reads, and its offline-render constraint.
  • Pending — the automatic busy indicator the Pending* members tune, and the Pending ambient.
  • component — components, render blocks, and the built-in elements a surface is built from.

Related

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…

Pending

When a control's action waits on the server, the platform shows a busy spinner and disables the control — but only…

component

The one archetype for all UI: a bounded reactive unit — typed props, reactive members (fields, `live`…