Unify Applications
Logo
Building a Module

Building a Module

Logo

6 mins READ

Where Modules Live

Every module in an app is listed under the Modules tab of the builder's navigator, kept separate from the app's pages. Opening a module from this tab launches it in the module builder.

unify-applications-building-a-module-01-module-builder.png
unify-applications-building-a-module-01-module-builder.png

A module you create from the Modules tab belongs to this app. You can embed it on any page of the app.

To use a module in other apps too, make it a global module. In the navigator, click the module in the Modules tab to open its Page Settings, open the menu at the top of the panel and choose Move to global. Turn on Remove from this application to delete the app-level module; existing placements switch to the new global module automatically. Leave it off to add an independent copy to the global library; later edits to the app-level module won't sync to it.

You can also create a global module directly from the Applications manager with Create Module. See Packages & Modules Screen.

Creating a New Module

  1. Open an application in the builder.

  2. In the left navigator, click the Modules tab.

  3. Click the Create new module button next to Search modules....

  4. A new, empty module is added to the app and you are taken straight into its builder.

The module belongs to the app from the moment it's created and can immediately be embedded on any page of that app.

The Module Builder Workspace

The module builder gives you the same toolset as the page builder, scoped to the one module:

ElementDescription
CanvasThe center area where you drop and arrange blocks. The module's entire layout lives here.
Left tool railAI Assistant, Design, Data, Hierarchy, Finder, Analytics, Saved Versions, and Settings — the same tools a page has.
Property panelOn the right, for the selected block.
HeaderShows the app name with a Module tag, the module's publish status, a device switcher, and a publish control. A back control returns you to the host app.

Note: A module is a single design surface. The module builder has no page switcher — a module holds one canvas, not a set of pages. When you need to reuse several distinct screens, build several modules, one per screen.

Module Inputs and Outputs

A module is not a sealed box. It exchanges values with wherever it is placed. You declare this contract in the module's settings. To open them, click the Module Settings (gear) icon next to the module's name at the top of the Hierarchy panel.

unify-applications-building-a-module-02-module-settings-inputs-outputs-events.png
unify-applications-building-a-module-02-module-settings-inputs-outputs-events.png

Privacy Settings

Choose whether the module can be embedded in public pages or apps. A Private module can only be used in private pages or apps. A Public module can be used in both public and private pages or apps. If you place a private module on a public page, visitors may not be able to see it.

Inputs

Named values the module accepts from each placement. Under Input, click Add Module Inputs to declare each field (name, type), or Use Code Snippet to describe the schema as code. Each placement supplies its own values. Inside the module, blocks read inputs as:

{{ pageInputs['inputKey'] }}

Output

Named values the module publishes back to the surrounding page. Under Output, click Add Module Outputs or Use Code Snippet to describe them. The module updates these at runtime, and the parent page reads them from the Module block's state:

{{ moduleBlockId['output']['outputKey'] }}

The Module block fires an On Output Change event whenever the output changes, regardless of how many output fields you declared.

Outbound events

Custom events the module can emit upward to its parent. You declare them in the module's settings under Outbound Events, each with an event type and a human-readable label.

Inbound events

Custom events the parent can push down into the module. You declare them in the module's settings under Inbound Events. The parent sends them via the Emit Inbound Event method on the Module block, specifying the event and an optional payload.

Tip: On the Module block's Events list you'll find On Output Change and each outbound event the module declares. Add a handler for the event you need. The event's payload is available as eventPayload.

Embedding a Module on a Page

  1. Open any page in the app builder.

  2. Add a Module block from the block picker.

  3. In the block's properties, select which module to embed. The picker lists modules from the **Current app** and **Common** (global) modules.

  4. Under Module Inputs, bind each input field to a value — a static value, a data source result, or an expression from the surrounding page.

  5. Under Events, add a handler for On Output Change to react when the module publishes new output values, or for any outbound event the module declares.

  6. Optionally enable Remember state when hidden if the module should preserve its state across hide/show cycles.

Web and Mobile Modules

The builder matches the app's platform. A module in a web app opens in the web module builder; a module in a mobile app opens in the mobile module builder with controls suited to that platform. The authoring model is the same — canvas, tools, header — but the surface reflects where the module will run.

Publishing a Module

A module has its own Publish button in the header, next to its publish status. In the builder, every placement shows the module's latest auto-saved design. The live app shows the module as it was last published, so publish the module to send your changes to visitors.

Editing the module changes every placement, because each placement is a live view of the module. There is no per-placement copy to edit in isolation — the per-placement lever is the module's inputs.

Trade-offs & Gotchas

  • Editing the module changes every placement. A change to the module — a new block, a restyle, a data-source swap — shows up in every placement in the builder as soon as it auto-saves, and in the live app once you publish the module. Plan module changes knowing every placement inherits them.

  • One module = one design surface. The module builder holds a single canvas with no page switcher. If a reusable flow needs several distinct screens, model each as its own module.

  • Input/output/event names must match exactly. The input names you bind under Module Inputs on the placement must match the input fields declared in the module. Output keys for reading must match the module's output field names. There is no compile-time validation — mismatches silently produce undefined.

  • The module's output is read off the block ID, not the module event name. Use {{ moduleBlockId['output']['key'] }} — not the event type string.

FAQs

How do I pass data from the host page into a module?

Declare inputs in the module's settings, then bind values to those inputs in the Module block's Module Inputs section. Inside the module, read them as {{ pageInputs['inputKey'] }}.

How does the module send data back to the host page?

The module publishes an output record. The host page reads it via {{ moduleBlockId['output']['outputKey'] }} and reacts using the On Output Change event on the Module block, which fires whenever any output value changes. The module can also emit its own outbound events, which you handle separately on the Module block.

Can a module contain multiple pages?

No. A module has a single design surface — the module builder has no page switcher. If you need several distinct screens in a reusable unit, build each as a separate module.

What's the difference between a module's outbound events and its output?

Both carry data from module to parent, but differently. The output is a persistent record the parent can bind to and read at any time. Outbound events are discrete signals fired at a specific moment — useful for one-time notifications like "form submitted." On the Module block's Events list, each outbound event the module declares appears alongside On Output Change, so you can add a separate handler for each. The event's payload is available as eventPayload.