# Navigation (/docs/products/dash-dots/developers/navigation)

A dot's open pages form a stack, like plates on a cookshop counter. Opening a page puts it on top, and Back takes it off again.

## Open and close pages

Open pages from an action with `this.navigation`. Hooks can't navigate (see [Page hooks](/docs/products/dash-dots/developers/pages-and-state#page-hooks)).

```ts
actions: {
  pay(state) {
    this.navigation.push('confirm', { amount: String(state.amount) });
  },
},
```

| Method                          | What it does                                                          |
| ------------------------------- | --------------------------------------------------------------------- |
| `push(page, options?)`          | Opens `page` on top                                                   |
| `replace(page, options?)`       | Opens `page` in place of this one, so Back skips it                   |
| `reset(page, options?)`         | Closes every page and opens `page`. Use it to go home after a payment |
| `back(delta?)`                  | Closes this page, or `delta` pages                                    |
| `pushForResult(page, options?)` | Opens `page` and waits for its [result](#results-from-a-page)         |
| `backWithResult(result)`        | Closes this page and hands back `result`                              |

- Every page you open must be in `pages` in `dot.ts`.
- Up to 16 pages can be open, and opening one more does nothing. On a long flow, use `replace` for steps the person shouldn't go back to.
- Back on the first page closes the dot.
- Only the page on top can navigate. A quick second tap on the same button does nothing, because the new page is already on top.

A page underneath keeps its state. Its `onShow` hook runs when it's back on top, which is a good moment to refresh. See [Page hooks](/docs/products/dash-dots/developers/pages-and-state#page-hooks).

## Pass data with launch options

Launch options are strings you hand to the page you open. It reads them in `onLoad`:

```ts title="pages/confirm/controller.ts"
onLoad(options) {
  this.setState({ amount: Number(options.amount ?? '0') });
},
```

Convert numbers yourself, as above. Pass ids, not whole objects.

## Results from a page

When the person should pick something on another page, use `pushForResult`. It opens that page and waits. You get whatever it passes to `backWithResult`, or `undefined` if the person goes back without choosing:

```ts title="pages/profile/controller.ts"
actions: {
  async chooseGenre() {
    const genre = await this.navigation.pushForResult<string>('pick-genre');
    if (genre) {
      this.setState({ genre });
    }
  },
},
```

```ts title="pages/pick-genre/controller.ts"
pick(_state, event: DataEvent<{ genre: string }>) {
  this.navigation.backWithResult(event.data.genre);
},
```

## Share links

Share in the dot's menu sends a link to your dot's first page, which is often enough.

To let a link open one page, such as a single concert, add `share` to its `definePage` with the launch options the link may carry:

```ts title="pages/concert/controller.ts"
import { CONCERTS } from '../../concerts';
import state from './state';

export default definePage({
  initialState: state,
  share: { options: ['concert'] },
  hooks: {
    onLoad(options) {
      const concert = CONCERTS.find((item) => item.id === options.concert) ?? null;
      this.setState({ concert });
    },
  },
});
```

The link looks like `https://dashit.to/d/k7Pq2/concert?concert=jazz-night`.

- Only the options in the list go in the link. Keep private ones off the list.
- Write the list as plain strings in `definePage`. A list held in a variable won't work.
- A link holds up to 20 options.

The link opens the shared page on top of the first page, and Back leads home. If the page isn't shareable, or your dot no longer has it, the person lands on the first page and Dash tells them the link isn't valid.

> **Check what a link carries:** Anyone can type a link by hand. Check the options in `onLoad`, as above, and show a friendly message when they don't match anything.

## Dash's bars

Dash shows a navigation bar at the top and a tab bar at the bottom. Set them with `configs` in `defineDot` for every page, in `definePage` for one page, or with `this.setNavigationBar()` and `this.setTabBar()` while it runs:

```ts
export default definePage({
  initialState: state,
  configs: {
    navigationBar: { title: 'Confirm payment' },
    tabBar: { hidden: true },
  },
});
```

The navigation bar takes `title`, `hidden`, `backgroundColor` and `textColor` (as `#RRGGBB`). Leave out `textColor` and Dash picks one that reads on the bar. Set an option to `undefined` to go back to Dash's default.

A title can be up to 60 characters, and Dash cuts a longer one. A title that names Dash or Monime shows your dot's name instead. `monime dot dev` warns you about both.

To give a page tabs of its own in place of Dash's, see [A page's own navigation](/docs/products/dash-dots/developers/components#a-pages-own-navigation).

When a page hides the navigation bar, Dash shows a capsule at the top right with your dot's icon and the menu button. Keep that corner of the page free.

## The dot's menu

The menu button in the navigation bar, ••• on iPhone and ⋮ on Android, opens the dot's menu. Its About screen lists your dot's [permissions](/docs/products/dash-dots/developers/security#permissions). [The dot's menu](/docs/products/dash-dots/how-customers-find-dots#the-dots-menu) lists everything in it.

## Close the dot

For a Done button on your last screen, call `this.dash.dot.close()`. The dot closes, and any Dash calls still running are cancelled.
