---
title: Flows
description: Flows record navigation edges between screens — documentation of intent and the input to reachability analysis, not the navigation mechanism; a timed link carries its delay.
status: shipped
url: https://getairframe.com/framewerk/core/flows
---

> Part of the Framewerk docs. Index of every page: /framewerk/llms.txt

# Flows

**Flows** record navigation edges between screens: documentation of intent and the input to reachability analysis — `navigate()` works whether or not an edge is declared.

## Examples

A single edge:

**One flow edge**

```json
{
  "formatVersion": "1.0",
  "screens": [
    {
      "id": "menu",
      "layout": {
        "_id": "menu-root",
        "type": "column",
        "gap": 12,
        "padding": 16,
        "children": [
          { "_id": "h", "type": "text", "variant": "heading", "content": "Menu" },
          { "_id": "go", "type": "button", "variant": "primary", "content": "Order", "action": "navigate(order)" }
        ]
      }
    },
    {
      "id": "order",
      "layout": { "_id": "order-root", "type": "text", "content": "Order screen" }
    }
  ],
  "flows": [{ "from": "menu", "to": "order", "trigger": "Order button" }]
}
```

An edge with transition metadata:

**A modal transition**

```json
{
  "formatVersion": "1.0",
  "screens": [
    {
      "id": "inbox",
      "layout": {
        "_id": "inbox-root",
        "type": "column",
        "gap": 12,
        "padding": 16,
        "children": [
          { "_id": "h", "type": "text", "variant": "heading", "content": "Inbox" },
          { "_id": "compose", "type": "button", "variant": "primary", "content": "Compose", "action": "navigate(compose)" }
        ]
      }
    },
    {
      "id": "compose",
      "layout": { "_id": "compose-root", "type": "text", "content": "Compose" }
    }
  ],
  "flows": [
    {
      "from": "inbox",
      "to": "compose",
      "type": "modal",
      "transition": { "name": "fade", "duration": 300 }
    }
  ]
}
```

## Anatomy

```json
{ "flows": [{ "from": "menu", "to": "order", "trigger": "Order button" }] }
```

Flows are documentation of intent, not the navigation mechanism — their value is analysis: the validator uses reachability to flag orphaned screens, and flows are what render as a map of the app.

A flow may carry **transition metadata** that animates the swap in playback:

```json
{ "from": "inbox", "to": "compose", "type": "modal",
  "transition": { "name": "fade", "duration": 300 } }
```

Names: `slide-left`, `slide-right`, `slide-up`, `slide-down` and `fade` move only the incoming screen; `push-left`, `push-right`, `push-up`, `push-down` move both like a navigation stack; `dissolve` cross-fades both; `shared` morphs every node whose `style.viewTransitionName` matches on both screens (View Transitions API, dissolve where it is missing); `none` suppresses a default. `easing` takes any CSS curve or `spring(mass, stiffness, damping)`.

Omitted metadata falls back to the flow type: `modal` presents as a sheet slide-up **above** the current screen, which stays mounted beneath a scrim (`overlay: false` takes the whole frame; `dim` sets the scrim, `closeOnOutside` makes the scrim navigate the reverse flow), `dismiss` animates the **outgoing** screen away (slide-down by default — the transition name on a dismiss flow describes how the departing screen leaves), and `navigate`/`replace` stay instant unless opted in.

A link that follows on its own after a wait carries `"trigger": "timeout"` and `delay`, the wait in milliseconds, so the map can draw it: `{ "from": "splash", "to": "home", "trigger": "timeout", "delay": 800 }`. The flow only records it; the source screen's [`onEnter`](/framewerk/core/actions.md#actions-that-run-without-a-press) is what plays it.

`flowPackages` group multi-step journeys (onboarding, checkout) into named sequences with per-step context.

## Stability

Flow fields (`from`, `to`, `trigger`, `delay`, `type`, `transition`) and the transition-name set are part of the format contract. Adding a transition name is additive; changing how an existing one animates is breaking.
