UI primitives

Add familiar Storeadmin controls around your embedded app for navigation, feedback, page actions, and unsaved work.

UI primitives let your app place a small set of controls in the surrounding Storeadmin interface. Use them for actions and status that belong to the current app screen. Your app still owns the content inside its embedded page. On iOS and Android, the supported primitives are toast, loading, and setting the title bar. Other controls described here require the web admin. After bridge.ready(), check bridge.supports(operation) before showing an action that depends on optional host UI.

Primitives cover controls in Storeadmin's chrome. To make the content inside your own page look native, use the App Bridge UI kit.

Show brief feedback#

Use bridge.toast(message, variant?) after a short action such as saving, copying, or completing a step. message is required and accepts up to 500 characters. variant can be "default", "success", or "error"; it defaults to "default".

app.js javascript
await bridge.toast("Campaign saved", "success");
A toast reading Campaign saved in the corner of Storeadmin
The toast as Storeadmin presents it.

Show ongoing work#

Call bridge.loading.start() while the current app view is waiting for work to finish, then call bridge.loading.stop(). Repeating either call is safe.

app.js javascript
bridge.loading.start();
try {
  await refreshCampaigns();
} finally {
  await bridge.loading.stop();
}
A thin dark loading bar sweeping along the top edge of the app area
The loading bar runs along the top of the app area; the page stays interactive.

Keep important status visible#

bridge.banner.show(options) displays a notice above the app until your app hides it or the merchant dismisses it. Use a banner for setup requirements, service interruptions, or another status that should remain visible. Supported tones are also available as bridge.banner.TONES.

Field

Required

Default

Limit or values

message

yes

—

1–1000 characters

tone

no

info

info, success, warning, or critical

title

no

empty

Up to 120 characters

dismissible

no

true

Boolean

action

no

none

{ id, content }; id up to 100 characters, content up to 80

The action emits banner:action with its id. Dismissing the banner emits banner:dismiss. Call bridge.banner.hide() when the status no longer applies.

app.js javascript
await bridge.banner.show({
  title: "Connection needed",
  message: "Reconnect your account to resume syncing.",
  tone: "warning",
  action: { id: "reconnect", content: "Reconnect" },
});

bridge.on("banner:action", ({ id }) => {
  if (id === "reconnect") openConnection();
});
A neutral banner with a message, an action button, and a dismiss control
An info banner with an action and dismiss.
A banner with a title and message and a heavier border for warning emphasis
A warning banner: emphasis comes from border weight, never color.

Protect unsaved work#

Call bridge.saveBar.show(options?) when a form becomes dirty and bridge.saveBar.hide() after a successful save or discard. Save emits savebar:save; Discard emits savebar:discard.

Field

Default

Limit or meaning

message

Unsaved changes

Up to 200 characters

saveLabel

Save

Up to 40 characters

discardLabel

Discard

Up to 40 characters

saveDisabled

false

Disables Save

loading

false

Shows Save in progress

app.js javascript
await bridge.saveBar.show({
  message: "Campaign has unpublished changes",
  saveLabel: "Publish",
});

bridge.on("savebar:save", async () => {
  await bridge.saveBar.show({ loading: true });
  await publishCampaign();
  await bridge.saveBar.hide();
});

Set the page title and actions#

bridge.titleBar.set(options) sets the title and optional actions for the current app screen. title is required and accepts up to 120 characters. Each action needs an id and content; up to three secondary actions are supported. Action clicks emit titlebar:action. Call bridge.titleBar.clear() to restore the default app header.

app.js javascript
await bridge.titleBar.set({
  title: "Campaigns",
  primaryAction: { id: "new", content: "New campaign" },
});

bridge.on("titlebar:action", ({ id }) => {
  if (id === "new") createCampaign();
});

Add app navigation#

bridge.nav.set({ items }) adds your app sections beneath the app in the Storeadmin sidebar. Provide 1–10 items. Every item needs an id and label; set current: true on the active item. A selection emits nav:navigate with the item id. Your app remains responsible for changing its own route and content. Call bridge.nav.clear() when the menu no longer applies.

app.js javascript
await bridge.nav.set({
  items: [
    { id: "overview", label: "Overview", current: true },
    { id: "settings", label: "Settings" },
  ],
});

bridge.on("nav:navigate", ({ id }) => {
  appRouter.open(id);
});

Use the full workspace#

bridge.fullscreen.enter() expands the embedded app to the available viewport. bridge.fullscreen.exit() returns to the standard Storeadmin layout. The host keeps an Exit fullscreen control available and emits fullscreen:change whenever the state changes.