# Navigate between screens

> Move forward and back between screens (push/pop) and pass data to the destination screen.

Source: https://crossfly.dev/docs/ui/navigation/navigate-between-screens — CrossFly documentation. Full docs as one file: https://crossfly.dev/llms-full.txt

# Navigate between screens

## What you will learn
- Move forward to a new screen (`show()`) and back (`hide()`).
- **Pass data** to the destination screen.
- Where to build each screen's UI.

## Prerequisites
Understand that every screen is a subclass of `Window` and that the UI is built in `onShow()`.

## Complete example (copy, paste and run)
```java
package com.exemplo;

import dev.crossfly.ui.*;
import dev.crossfly.ui.layout.*;
import dev.crossfly.ui.style.*;

/** Runnable main screen. Point the launcher (classname) and run: gradlew :lwjgl3:run */
public class MainWindow extends Window
{
   @Override
   public void onShow() throws Exception
   {
      super.onShow();
      setLayout(new VerticalLayout());

      add(LAY_AUTO, new Label("Lista"));

      Button abrir = new Button("Abrir detalhe do item 42");
      abrir.onAction(c -> new TelaDetalhe(42).show());   // push (advance) — data via the constructor
      add(LAY_AUTO, abrir);
   }
}

/** Second screen: receives the id via the constructor and returns with hide(). */
class TelaDetalhe extends Window
{
   private final int id;

   public TelaDetalhe(int id) { this.id = id; }   // data comes via the constructor

   @Override
   public void onShow() throws Exception
   {
      super.onShow();
      setLayout(new VerticalLayout());

      add(LAY_AUTO, new Label("Detalhe do item " + id));

      Button voltar = new Button("Voltar");
      voltar.onAction(c -> hide());   // pop (back)
      add(LAY_AUTO, voltar);
   }
}
```
> The snippets below show **only the core** (what goes inside `onShow()`). To run them, place them in the `MainWindow` skeleton above.

## Move forward (push) and back (pop)
```java
public class TelaLista extends Window {
   @Override public void onShow() throws Exception {
      super.onShow();
      setLayout(new VerticalLayout());
      Button abrir = new Button("Abrir detalhe");
      abrir.onAction(c -> new TelaDetalhe(42).show());   // push (advance)
      add(LAY_AUTO, abrir);
   }
}

public class TelaDetalhe extends Window {
   private final int id;
   public TelaDetalhe(int id) { this.id = id; }          // data comes via the constructor
   @Override public void onShow() throws Exception {
      super.onShow();
      setLayout(new VerticalLayout());
      add(LAY_AUTO, new Label("Detalhe do item " + id));
      Button voltar = new Button("Voltar");
      voltar.onAction(c -> hide());                       // pop (back)
      add(LAY_AUTO, voltar);
   }
}
```

## Pass data to the next screen
There are no "route arguments". **Pass them through the constructor** of the destination `Window` (like `id` above).
For objects, pass the reference: `new TelaCliente(cliente).show();`.

## Where to build the UI
- **`onShow()`** (with `super.onShow()`): here `Screen.width/height` and the window bounds are already valid.
- **Do not** build in the constructor — the bounds may not be ready.

## Best practices
- Load data **off the paint thread** and return with `Component.onUI(...)` to populate the UI.
- Release resources (timers, cursors) in `onRemove()`.

## Common mistakes
- Building the UI in the constructor (invalid bounds) or forgetting `super.onShow()`.
- Expecting a "back-stack with named arguments" — pass data through the constructor.

## See also
- [Returning values from a screen](/docs/ui/navigation/returning-results) · [The window stack](/docs/ui/navigation/the-window-stack)
