Unify Logo Footer.svg
Unify Applications
Logo
Binding Context

Binding Context

Logo

5 mins READ

Binding Context

Every expression on a page evaluates against one shared namespace — a picture of everything the page knows at that moment. Blocks, data sources, page variables, and page functions sit at the top level under their own names; everything else lives under a fixed, well-known name like userContext or theme. When any part of this picture changes, every expression that reads it recomputes.

Page Entities (Named by You)

Blocks, data sources, page variables, and page functions are spread at the top level of the context under their names. You reference them directly — no namespace prefix required.

Entity typeWhat it exposesExample expressions
Block (by its name)The block's exposed state — its value, selection, loading flags — plus any methods it registers (callable directly).{{ email_input.value }} {{ orders_table.selectedRow.id }} {{ my_form.submitForm() }}
Data source (by its name)data (transformed result), rawData (untransformed), isLoading, isFetching, error, inputs. A trigger() method re-runs it on demand. For infinite sources: also hasNextPage and isFetchingNextPage.{{ orders_query.data.objects }} {{ orders_query.isLoading }} {{ orders_query.error?.message }}
Page variable (by its name){ value, setValue } — the bare name is the whole object. Read .value for the current value; call .setValue(x) to update it.{{ selected_tab.value }} {{ selected_tab.setValue('billing') }}
Page function (by its name){ value, error, isEvaluated } — the computed result is at .value. A manual function also has a .trigger() method.{{ format_title.value }} {{ format_title.trigger() }}

Warning: Writing {{ selected_tab }} returns the object { value, setValue }, which renders as [object Object] in a text block. Always append .value: {{ selected_tab.value }}.

Fixed Namespaces (Always Available)

These names are always in scope and do not depend on what blocks or data sources you've added to the page.

NamespaceWhat it holdsExample
userContextThe signed-in user: id, email, name, username, locale, plus any org-specific extras under userContext.context.{{ userContext.email }}
pageInputsValues passed into this page — by a navigation action, a parent page, or an embed. Never populated from the URL.{{ pageInputs.customerId }}
pageParamsNamed path segments from the page's route. The orderId in /orders/:orderId is here — not in pageInputs, and not in the query string.{{ pageParams.orderId }}
locationThe current URL broken up: href, hostname, pathname, search (raw query string), hash, pathParams (same as pageParams).{{ location.pathname }} {{ location.search }}
themeActive appearance: colorScheme ('light' or 'dark'), activeTheme, availableThemes.{{ theme.colorScheme === 'dark' ? darkLogo : lightLogo }}
utilsBuilt-in helpers for dates, numbers, JSON, and downloads. See Built-in Utilities.{{ utils.formatDate(order.createdAt, 'dd MMM yyyy') }}
envVariablesEnvironment variables configured for the app.{{ envVariables.API_BASE_URL }}
localStorageValues stored in browser localStorage. Has a setValue(key, val) method and a clear() method.{{ localStorage.draftFilters }}
sessionStorageValues stored in browser sessionStorage. Has a clear() method. Note: setValue() on sessionStorage does not persist — use the Set Interface Session Storage action instead.{{ sessionStorage.tempToken }}
interfaceRecordThe app itself: id, name, logo metadata, and navigation structure.{{ interfaceRecord.name }}
mediaUploadsFiles selected in file-upload blocks, keyed by block name.{{ mediaUploads.receipt_upload }}
appsAndIntegrationsResults from platform integrations (e.g. payment confirmation details from Razorpay).{{ appsAndIntegrations.razorpay.paymentId }}
actionsTwo callable utilities: emitPageEvent({ name }) and showNotification({ title }) — same as the visual actions, invokable from any expression or script.{{ actions.showNotification({ title: 'Saved' }) }}
deviceContext(Mobile apps only) Device state: battery saver mode, permission grants, location authorization (always / while-in-use / denied), whether location is spoofed.{{ deviceContext.permissions.camera }}

Reading a Value from the URL

Three namespaces look similar but come from different sources:

NamespaceWhat it holdsExample
pageParams.orderIdNamed path segments — the orderId in /orders/:orderId. Same value as location.pathParams.orderId.For route-based IDs like /customers/42
location.searchThe raw query string: ?status=open&page=2. Parse it for specific keys.For URL query parameters
pageInputs.customerIdValues another page, a parent page, or an embed handed in directly. Never from the URL.For values passed via the Navigate action

Row-scoped Names

Inside a Repeatable or Table, three extra names exist that don't exist anywhere else: currentRow, currentIndex, and currentPrimaryKey. They resolve per row. See Row-scoped Bindings for the full story.

Reserved Names

Some names are reserved — the builder rejects them for blocks, data sources, variables, and functions so they can never shadow something a binding expects. The blocked set includes:

  • All fixed namespace names (location, utils, theme, userContext, pageInputs, pageParams, envVariables, etc.)

  • Per-entity member names: value, instances, context, item, inputs

  • Browser globals: window, document, console, navigator, history, localStorage, sessionStorage

  • Common built-ins: Array, Object, String, Number, Boolean, Date, Math, JSON, Promise, Map, Set

  • Language keywords: for, class, select, from, def, and others from JavaScript, SQL, and Groovy

Scope Across Embedded Pages

An embedded page — a module, a template component, or a copilot thread — evaluates against its own blocks, pageInputs, and pageParams, separate from the page hosting it. App-wide values stay shared: userContext, theme, envVariables, location, and browser storage are available everywhere.

Modals, Drawers, and Bottom Sheets do not get their own namespace — they are blocks on the page and share the same context as everything else on it.

Common Questions

How do I get the logged-in user's email?

{{ userContext.email }} // Also available: userContext.id, userContext.name, userContext.locale // Org-specific extras: {{ userContext.context.department }}

How do I check if the app is in dark mode?

{{ theme.colorScheme === 'dark' }} // Use in a ternary: {{ theme.colorScheme === 'dark' ? logoDark : logoLight }}

Why does my page variable show [object Object]?

// Wrong — the bare name is { value, setValue } {{ my_var }} // Correct — append .value {{ my_var.value }}

How do I emit a page event from inside a script?

{{ actions.emitPageEvent({ name: 'orderPlaced', payload: { id: order.id } }) }} {{ actions.showNotification({ title: 'Order saved', type: 'success' }) }}