Skip to content

Surfaces vs modals vs intents vs events

The SDK gives you four ways for apps to work together. They are easy to confuse because several can solve the same problem badly. Here is what each is for.

An intent is a request with a reply, an event is a broadcast with no reply, a surface is live UI inline, and a modal is an overlay on top.
  • Intent — a named, versioned capability call. One app asks another to do something or return something (invoke), and the provider answers (provide). Request/response, point-to-point via the shell. Reach for this when you need data or an action from another app and you want a result back.
  • Event — a fire-and-forget broadcast on a topic (publish / subscribe). No response, no caller. The platform’s own session.changed and theme.changed are events. Reach for this when something happened and any number of apps might care, but you do not need an answer.
  • Surfacelive UI from another app, embedded inline in yours. The other app renders it; you host it. Reach for this when you want to show another app’s view in place — an invoice list inside a customer record — not just its data.
  • Modal — a surface used as a top-level overlay. The shell owns the frame; the body is one of your own surfaces. Reach for this when you need a focused, above-everything interaction (an edit form, a confirm) that should float over all chrome.
You want…UseGet a result?Whose UI?
data or an action from another appintentyesnone (data)
to announce something happenedeventnonone
to embed another app’s view inlinesurfacen/athe provider’s
a focused overlay of your own UImodalyes (on close)your own
  • Using an event when you need an answer. Events have no response channel. If you need a result, it is an intent.
  • Using an intent to move UI. Intents move data and actions, not rendered views. If you find yourself shipping HTML through an intent payload, you wanted a surface.
  • Building your own overlay instead of a modal. A modal stacks above all platform chrome and the shell owns its escape and sizing; an in-app overlay inside your iframe cannot escape your frame.