> ## Documentation Index
> Fetch the complete documentation index at: https://docs.getflowpilot.io/llms.txt
> Use this file to discover all available pages before exploring further.

# Persistent UI (zones)

> Build a navigation bar, footer, or overlay that stays on screen while the user moves through a flow.

A **zone** is UI that lives outside the individual screens and stays put as the user moves between them. Zones are the right place for a back button, a progress bar, a sticky "Continue" footer, or a floating badge. You build a zone the same way you build a screen: it holds a regular component tree.

<Note>
  Zones replace the old `chrome` model. `FlowDefinition.chrome` is **deprecated** and only kept so old flows keep working. Always build persistent UI with zones. If you see "chrome" anywhere, treat it as the legacy name for the same idea.
</Note>

## The three zones

A flow has one optional `persistentUI` object with up to three zones:

| Zone           | Schema field    | Where it sits                   | Notes                                              |
| -------------- | --------------- | ------------------------------- | -------------------------------------------------- |
| Navigation Bar | `navigationBar` | Pinned to the top               | Occupies layout space. Content sits below it.      |
| Footer         | `footer`        | Pinned to the bottom            | Occupies layout space. Content sits above it.      |
| Overlay        | `overlay`       | Floating layer over the content | Does not push content up or down. Rendered on top. |

The navigation bar and footer hold a normal `ComponentNode` tree (usually a stack with buttons, text, or a progress bar). The overlay is the same, but it is drawn as a floating layer rather than taking up vertical space.

## Turn on zones

Zones live in the **Layers** panel (Advanced), above the screen list.

<Note>
  In [Simple mode](/editor/editing-modes), zones live in the pinned **Persistent Zones** card at the top of the [Screens panel](/editor/screens-panel). Expand the card to add and edit zones (it reuses the same zone tree), or click **Set up persistent zones** if the flow has none yet. The steps below describe the Advanced Layers panel; the zone model is the same.
</Note>

<Steps>
  <Step title="Open the Layers panel">
    In the editor, open the left **Layers** tab. The persistent zones section is at the top, before the list of screens.
  </Step>

  <Step title="Click Add Persistent Zones">
    If a flow has no zones yet, you see a single **Add Persistent Zones** button. Click it.
  </Step>

  <Step title="Two zones appear">
    This creates a **Navigation Bar** and a **Footer**, both visible and empty, each with safe area turned on and a transition mode of **Persistent**. They show as collapsible rows in the Layers panel.
  </Step>
</Steps>

<Warning>
  **Add Persistent Zones creates only the navigation bar and footer.** The current editor build does not provide a control to add the **overlay** zone from this panel. The overlay is a real, supported zone (the SDKs render it), but it only appears in the editor if the flow's JSON already defines it (for example from a template or a hand edited schema). Treat the overlay as schema and SDK level for now.
</Warning>

## Add components to a zone

Once a zone exists, fill it like a screen.

* **Drag from Insert.** Select the zone (or a stack inside it), then open **Insert** and drag a **Component** or a **Block** in. The **Chrome** blocks (Back Button, Close Button, Progress Bar) are built for zones.
* **Use the zone menu.** Hover a zone row and click the `...` (more) icon, then **Add Element** and pick a component.
* **Reorder.** Drag component rows within the zone to reorder, or drop them into a stack to nest them.

The Chrome blocks are not special component types. They are ordinary nodes with preset settings:

| Block        | Component                     | Behavior                   |
| ------------ | ----------------------------- | -------------------------- |
| Back Button  | `button` (icon `ChevronLeft`) | `onPress` runs `goBack`    |
| Close Button | `button` (icon `X`)           | `onPress` runs `closeFlow` |
| Progress Bar | `progress` in `auto` mode     | Auto-tracks flow progress  |

See [Blocks](/editor/blocks) for the full catalog and [Components](/editor/components) for the primitive list.

### Selecting a zone vs a component in it

Clicking a **zone row** selects the zone's root stack and shows the zone's properties. Clicking a **component row inside** the zone selects that component and shows its properties. The breadcrumb at the top of the properties panel tells you which zone you are in (Navigation Bar, Footer, or Overlay).

Each zone row also has an **eye** toggle that shows or hides the **whole zone** across the entire flow. Each component inside a zone has its own eye toggle. These are global to the flow, not per screen (for per screen control, see [Per-screen overrides](#per-screen-overrides) below).

## Zone properties

Select a zone (click its row) to edit the zone. The panel is the same Layout / Style / Logic layout used for screen components, plus two zone level controls at the top (navigation bar and footer only):

| Control        | What it sets                                                                                                           | Schema                    |
| -------------- | ---------------------------------------------------------------------------------------------------------------------- | ------------------------- |
| **Safe Area**  | Respect the device safe area (notch at top, home indicator at bottom) so content does not sit under it. On by default. | `props.safeArea`          |
| **Transition** | How the zone behaves when the screen content changes. Defaults to **Persistent**.                                      | `behavior.transitionMode` |

Everything else about a zone is set on its **root stack**:

* **Background**: select the zone's root stack, open the **Style** tab, and use the **Layer** section (set a fill and color). The renderer uses the zone background, falling back to the root stack's background.
* **Padding**: use the root stack's **Spacing** section. Safe area is added on top of this padding, not instead of it.
* **Layout** (axis, alignment, spacing): the root stack's **Stack Settings**, exactly like any other stack. See [Layout and sizing](/editor/layout-and-sizing).

<Note>
  The overlay zone does not show the Safe Area or Transition controls. Its alignment and touch behavior are schema properties (see [Overlay alignment and passthrough](#overlay-alignment-and-passthrough)).
</Note>

## Transition modes

The **Transition** dropdown on the navigation bar and footer offers four modes, defined in the schema as:

| Mode          | Meaning                                                                                  |
| ------------- | ---------------------------------------------------------------------------------------- |
| `persistent`  | Zone stays visually fixed. No animation. This is the default and the most common choice. |
| `crossfade`   | The zone's content cross-fades when it changes between screens.                          |
| `reflow`      | Layout changes (size, position) animate smoothly.                                        |
| `participate` | The zone transitions together with the screen content, inside the animation container.   |

<Warning>
  **The iOS SDK currently implements two behaviors, not four.** It animates the zone on a screen change only for `crossfade` and `reflow` (both use the same zone animation), and keeps the zone fixed for `persistent` and `participate`. So today `reflow` behaves like `crossfade`, and `participate` behaves like `persistent`. Whether the whole flow transitions as one unit is governed flow wide by `settings.persistDuringTransition` (default `true`, zones stay fixed), which the editor does not expose.
</Warning>

Use `persistent` unless you have a clear reason to animate the bar. Animating a navigation bar or footer on every screen change is usually distracting.

## Overlay alignment and passthrough

The overlay zone has two extra schema properties that control how it floats:

| Property      | Values                                                                                                           | Default          | Meaning                                                                                                             |
| ------------- | ---------------------------------------------------------------------------------------------------------------- | ---------------- | ------------------------------------------------------------------------------------------------------------------- |
| `alignment`   | `topLeading`, `top`, `topTrailing`, `leading`, `center`, `trailing`, `bottomLeading`, `bottom`, `bottomTrailing` | `bottomTrailing` | Where the overlay content sits within the content area.                                                             |
| `passthrough` | `true` / `false`                                                                                                 | `false`          | When `true`, taps pass through the overlay to the content below. When `false`, the overlay blocks taps in its area. |

<Warning>
  These two properties are honored by the SDKs and the editor preview, but the editor does **not** currently surface controls for them. To set overlay alignment or passthrough, you edit the flow schema directly.
</Warning>

## Per-screen overrides

By default a zone shows on every screen. You can change that per screen, and the editor now exposes several per-screen controls:

* **Hide all zones** (`screenSettings.hideAllZones`): in Advanced, select a screen and open its **Behavior & Layout** section (see [The properties panel](/editor/properties)) to hide the navigation bar, footer, and overlay on this one screen. Off by default. This is the usual way to give a welcome or success screen a clean, full-bleed look.
* **Hide a single zone on one screen** (`screenSettings.<zone>.visible`): in [Simple mode](/editor/editing-modes), each screen card in the [Screens panel](/editor/screens-panel) has an eye icon with a **"Show navigation bar / footer / overlay here"** switch per zone. Screens that hide a zone get an amber badge. This writes the per-zone visibility override.
* **Per-component prop overrides on one screen** (`screenSettings.<zone>.componentProps`): in Advanced, select a zone component and use the **All screens | This screen** scope switcher at the top of its properties. "This screen" edits only that screen's copy of the component (for example a different footer button label on the last screen); a **Zone Overrides** section in the screen's properties lists and resets these per-screen patches. Interactions, animations, and renames always edit the shared component.

Some finer per-screen control is still schema and SDK level only:

| Capability                                  | Schema field                                                   | Status                                 |
| ------------------------------------------- | -------------------------------------------------------------- | -------------------------------------- |
| Replace a zone's whole layout on one screen | `screenSettings.<zone>.replaceLayout`                          | SDK and schema only, no editor control |
| Override the progress value on one screen   | `screenSettings.progressOverride` (0 to 1, or `null` for auto) | SDK and schema only, no editor control |

<Note>
  A zone only allows per-screen overrides if its `behavior.allowScreenOverride` is `true` (the default). The editor sets this on when it creates the zones and does not expose a toggle for it.
</Note>

## Progress bars in a zone

A **Progress Bar** block in a zone runs in `auto` mode, which tracks the user's position through the flow automatically. Two settings on the **screen** affect the value it shows:

* **Include in Progress Steps** (`includeInProgress`, on by default): whether this screen counts toward the total. Turn it off for screens that should not advance the bar (for example an interstitial).
* **Progress override** (`screenSettings.progressOverride`): forces a specific value (0 to 1) on a screen. Schema and SDK only for now (see the table above).

Both are documented on [The properties panel](/editor/properties).

## Example: a persistent nav bar and footer

Goal: a back button and a progress bar that stay across every step, hidden on the welcome screen, plus a sticky "Continue" footer.

<Steps>
  <Step title="Add the zones">
    In the **Layers** panel, click **Add Persistent Zones**. You now have a Navigation Bar and a Footer.
  </Step>

  <Step title="Fill the navigation bar">
    Select the **Navigation Bar**. Its root stack is already horizontal with space between its children. Open **Insert**, then **Blocks**, then **Chrome**, and add a **Back Button** and a **Progress Bar**. Drag them so the back button is on the left and the progress bar is centered.
  </Step>

  <Step title="Fill the footer">
    Select the **Footer**. Add a **Button** (from Insert), set its label to "Continue", and on the **Logic** tab add an **On Tap** interaction with a `goNext` action. Because it is in the footer, it stays pinned to the bottom on every screen.
  </Step>

  <Step title="Hide the zones on the welcome screen">
    Select your first (welcome) screen. In the properties panel open **Behavior & Layout** and turn on **Hide All Zones**. The welcome screen now renders full bleed, with no bar or footer.
  </Step>

  <Step title="Preview">
    Open **Preview** (`⌘.`). Move past the welcome screen and the bar and footer appear and stay fixed while the screen content transitions. The progress bar fills as you advance.
  </Step>
</Steps>

The resulting `persistentUI` looks like this in the flow schema:

```json theme={null}
{
  "persistentUI": {
    "navigationBar": {
      "id": "zone_navbar_1",
      "visible": true,
      "layout": {
        "id": "navbar_stack",
        "type": "stack",
        "props": { "direction": "horizontal", "align": "center", "justify": "space-between" },
        "children": [
          {
            "id": "back_btn",
            "type": "button",
            "props": { "iconName": "ChevronLeft", "backgroundColor": "transparent" },
            "interactions": [
              { "id": "i1", "event": "onPress", "actions": [{ "kind": "goBack" }] }
            ]
          },
          {
            "id": "progress_1",
            "type": "progress",
            "props": { "mode": "auto", "color": "#4F46E5", "height": 4 }
          }
        ]
      },
      "behavior": { "allowScreenOverride": true, "transitionMode": "persistent" },
      "props": { "safeArea": true }
    },
    "footer": {
      "id": "zone_footer_1",
      "visible": true,
      "layout": {
        "id": "footer_stack",
        "type": "stack",
        "props": { "direction": "vertical", "align": "stretch", "justify": "flex-end" },
        "children": [
          {
            "id": "continue_btn",
            "type": "button",
            "props": { "text": "Continue" },
            "interactions": [
              { "id": "i2", "event": "onPress", "actions": [{ "kind": "goNext" }] }
            ]
          }
        ]
      },
      "behavior": { "allowScreenOverride": true, "transitionMode": "persistent" },
      "props": { "safeArea": true }
    },
    "settings": { "persistDuringTransition": true }
  }
}
```

The welcome screen carries the override:

```json theme={null}
{
  "id": "screen_welcome",
  "kind": "screen",
  "name": "Welcome",
  "layout": { "id": "root", "type": "stack" },
  "screenSettings": { "hideAllZones": true }
}
```

An overlay zone (schema only for now) that floats a badge in the top trailing corner and lets taps reach the content below:

```json theme={null}
{
  "overlay": {
    "id": "zone_overlay_1",
    "visible": true,
    "layout": { "id": "overlay_stack", "type": "stack", "children": [] },
    "behavior": { "allowScreenOverride": true },
    "props": { "alignment": "topTrailing", "passthrough": true }
  }
}
```

## Common mistakes

* **Putting persistent navigation inside a screen.** A back button or progress bar added to a screen's Root Stack does not persist. It is rebuilt and re-animated on every screen change, and it disappears when you navigate. Put anything that should stay across screens in a zone.
* **A non-passthrough overlay blocking the UI.** An overlay with `passthrough: false` blocks taps in its whole area. If the overlay fills the content area, it can swallow taps meant for the screen. Keep the overlay content small, or set `passthrough: true`.
* **Forgetting safe area.** With safe area off, navigation bar content can sit under the notch and footer content under the home indicator. Leave **Safe Area** on unless you are deliberately drawing into those areas.
* **Animating zones by habit.** Setting Crossfade or Reflow makes the bar move on every screen change. For most flows `persistent` (fixed) reads better.
* **Looking for per-zone hide in the wrong place.** Hiding *all* zones on a screen is the **Hide all zones** toggle in a screen's Behavior & Layout (Advanced). Hiding *one* zone on a screen is the per-screen eye toggle on the [Screens panel](/editor/screens-panel) card (Simple).

## Related pages

* [Components](/editor/components)
* [Blocks](/editor/blocks)
* [The properties panel](/editor/properties)
* [Build a multi-step flow](/editor/multi-step-flows)
* [Flow schema reference](/reference/flow-schema)
