Skip to content
Subha Sundar Das edited this page Jul 14, 2026 · 1 revision

Navigation and focus solve two different problems in a terminal application.

  • Navigation decides which screen is currently displayed.
  • Focus decides which component receives keyboard input.

Although they often work together, they are completely independent systems.


Navigation

RetUI manages screens using a stack.

Each new screen can be pushed onto the stack, replaced, or removed, making navigation similar to a web browser's history.


Push a Screen

Navigate to a new screen while keeping the current one in the history.

retui.PushScreen("settings")

The user can later return using PopScreen().


Pop a Screen

Go back to the previous screen.

retui.PopScreen()

Replace a Screen

Replace the current screen without keeping it in history.

retui.ReplaceScreen("login")

This is useful after:

  • Login
  • Logout
  • Authentication redirects
  • Splash screens

The previous screen is discarded, so pressing Back won't return to it.


Current Screen

Read the active screen.

screen := retui.CurrentScreen()

Example:

if retui.CurrentScreen() == "settings" {
    // Show settings
}

Can Go Back?

Determine whether a previous screen exists.

retui.CanPopScreen()

Useful for deciding whether to display a Back button.


Screen Stack Size

Get the number of screens currently in the navigation stack.

retui.ScreenStackSize()

Screen Stack Snapshot

Retrieve the complete navigation stack.

stack := retui.ScreenStackSnapshot()

Useful for:

  • Breadcrumbs
  • Debugging
  • Navigation history

Initial Screen

Choose the application's first screen.

retui.SetInitialScreen("home")

Call this once during application startup.


Reset Navigation

Clear the entire navigation history.

retui.ResetScreenStack("login")

This is commonly used after logout.


Navigation Example

func App() retui.Element {

    switch retui.CurrentScreen() {

    case "home":
        return HomeScreen()

    case "settings":
        return SettingsScreen()

    default:
        return retui.Text(
            "404 - Not Found",
            retui.NewStyle().
                Foreground(retui.Red),
        )
    }

}

Whenever the current screen changes, RetUI automatically:

  • Resets component state
  • Rebuilds the UI
  • Re-renders the screen

No manual cleanup is required.


Focus

Only one interactive component receives keyboard input at a time.

That component is said to have focus.


Set Focus

Move keyboard focus to a component.

retui.SetFocus("name-input")

Current Focus

Retrieve the focused component.

retui.CurrentFocus()

Check Focus

Determine whether a component currently has focus.

retui.IsFocused("name-input")

Clear Focus

Remove focus from all components.

retui.Blur()

Focus Example

Most built-in components expose a Focused() method.

components.TextInput().
    ID("name").
    Focused(
        retui.IsFocused("name"),
    ).
    Render()

Focus Order

Specify the order components should receive focus.

retui.SetFocusOrder([]string{
    "name",
    "email",
    "submit",
})

Users can then navigate using Tab and Shift+Tab.

if retui.CurrentKey.Code == retui.KeyTab {
    retui.FocusNext()
}

if retui.CurrentKey.Code == retui.KeyShiftTab {
    retui.FocusPrev()
}

Focus automatically wraps around when reaching the beginning or end of the list.


Temporary Focus (Modals)

Dialogs and popups often need temporary focus.

RetUI provides a focus stack for this purpose.

retui.PushFocus("confirm-button")

Later:

retui.PopFocus()

The previous focus is restored automatically.

Typical use cases include:

  • Dialogs
  • Confirmation boxes
  • Popups
  • Floating windows

Capture Focus

Sometimes a component must receive every keyboard event.

Dropdowns are a common example.

retui.CaptureFocus("country-picker")

Release capture:

retui.ReleaseCaptureFocus()

While capture is active:

  • Only the captured component receives keyboard events.
  • All other focused components are ignored.

Capture State

Read the captured component.

retui.CapturedFocus()

Check whether a component currently owns the capture.

retui.IsCaptured("country-picker")

Reading Keyboard Input

Focus tells a component that it is active.

Hooks allow it to read keyboard events.


UseFocusedKeySimple

For ordinary components.

key, active := retui.UseFocusedKeySimple(
    retui.IsFocused("counter"),
)

if active {

    switch key.Code {

    case retui.KeyUp:
        // Handle key

    }

}

UseFocusedKey

Use this hook for components that may capture focus.

key, active := retui.UseFocusedKey(
    "country-picker",
    retui.IsFocused("country-picker"),
)

if active {

    switch key.Code {

    case retui.KeyEnter:
        retui.ReleaseCaptureFocus()

    }

}

This hook automatically respects focus capture, preventing multiple components from handling the same key press.


Complete Example

func Counter() retui.Element {

    key, active := retui.UseFocusedKeySimple(
        retui.IsFocused("counter"),
    )

    count, setCount := retui.UseState(0)

    if active {

        switch key.Code {

        case retui.KeyUp:
            setCount(count + 1)

        case retui.KeyDown:
            setCount(count - 1)

        }

    }

    return retui.Text(
        fmt.Sprintf("Count: %d", count),
        retui.NewStyle(),
    )

}

Navigation Summary

Function Description
PushScreen(id) Navigate to a new screen
PopScreen() Return to the previous screen
ReplaceScreen(id) Replace the current screen
CurrentScreen() Get the active screen
CanPopScreen() Check whether Back is available
SetInitialScreen(id) Set the application's first screen
ResetScreenStack(id) Clear navigation history
ScreenStackSize() Number of screens in the stack
ScreenStackSnapshot() Retrieve the navigation stack

Focus Summary

Function Description
SetFocus(id) Focus a component
CurrentFocus() Get the focused component
IsFocused(id) Check whether a component is focused
Blur() Remove focus
SetFocusOrder() Define Tab navigation
FocusNext() Move to the next component
FocusPrev() Move to the previous component
PushFocus() Temporarily save and change focus
PopFocus() Restore previous focus
CaptureFocus() Capture all keyboard events
ReleaseCaptureFocus() Release captured focus
CapturedFocus() Get captured component
IsCaptured() Check capture ownership

Keyboard Hooks

Hook Purpose
UseFocusedKeySimple() Read keyboard input for normal focused components
UseFocusedKey() Read keyboard input while supporting focus capture

Remember

Navigation answers:

"Which screen is currently visible?"

Focus answers:

"Which component receives keyboard input?"

The two systems work together but remain independent. Every RetUI application uses both to create responsive, keyboard-friendly terminal interfaces.

Clone this wiki locally