Skip to content
Subha Sundar Das edited this page Jul 14, 2026 · 6 revisions

Before learning individual components, it helps to understand how RetUI works under the hood.

Good news: there are only a handful of ideas to learn, and they all build on each other.


1. Everything Is a Component

In RetUI, your application is built by combining small components.

A component is simply a Go function that returns a retui.Element.

func Greeting() retui.Element {
    return retui.Text("Hello, World!", retui.NewStyle())
}

You can use this component anywhere in your application:

func App() retui.Element {
    return Greeting()
}

Think of components as building blocks. Instead of writing one giant function, you build many small, reusable pieces — then combine them.


2. Components Can Be Nested

Components can contain other components. Box is the primary layout primitive in RetUI — it's a flexbox-style container that arranges its children, and every layout (rows, columns, panels, forms) is built from it.

func App() retui.Element {
    return retui.Box(
        retui.Props{Direction: retui.Column},
        retui.NewStyle(),
        retui.Text("Welcome", retui.NewStyle().Bold(true)),
        retui.Text("Hello RetUI!", retui.NewStyle()),
    )
}

You can keep nesting boxes to build more complex interfaces:

Box (Column)
├── Text ("Welcome")
└── Text ("Hello RetUI!")

Real apps might look more like this:

Box ("Dashboard", Column)
├── Box (Row)
│   ├── UserPanel
│   └── StatsPanel
└── Footer

3. The UI Rebuilds Automatically

Whenever your application's state changes, RetUI rebuilds the UI.

Don't worry — this doesn't mean the entire terminal redraws. RetUI compares the old UI with the new one and updates only the parts that changed.

Example: if only a counter changes —

Before:

Counter: 5

After clicking a button:

Counter: 6

Only the number is updated. Everything else on screen stays untouched. This keeps applications fast and responsive, even as they grow.


4. State Makes Your UI Dynamic

State is simply data that can change over time.

Without state, text is frozen forever:

retui.Text("Counter: 0", retui.NewStyle())

With state, it can update:

count, setCount := retui.UseState(0)

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

Later, update it from anywhere — like a button handler:

setCount(count + 1)

RetUI automatically refreshes the screen to reflect the new value.

Full example — a working counter:

import (
    "fmt"
"github.com/subhasundardass/retui/retui"
"github.com/subhasundardass/retui/retui/components"

)

func Counter() retui.Element { count, setCount := retui.UseState(0)

return retui.Box(
    retui.Props{Direction: retui.Column, Gap: 1},
    retui.NewStyle(),
    retui.Text(fmt.Sprintf("Counter: %d", count), retui.NewStyle()),
    components.Button().
        ID("increment").
        Label("Increment").
        OnClick(func(id string) {
            setCount(count + 1)
        }).
        Render(),
)

}


5. Hooks Let Components Remember Things

Hooks let a component remember information between renders — like state or side effects.

The hooks available today are:

Hook Purpose
UseState Store a value that can change, keyed by render position
UseStateKeyed Like UseState, but keyed by a stable string — use when the number of hook calls can vary between renders (e.g. expandable tree nodes)
UseEffect Run code in response to changes (e.g. on mount, on dependency change), with optional cleanup
UseContext / CreateContext Share a value down the component tree without passing it manually through every layer

Don't worry if these are new — each hook has its own dedicated guide later in the documentation. For now, just know: hooks are how components remember things.


6. Layout Controls Position

Components don't decide where they appear on screen — the layout system does, via Box and its Direction prop.

retui.Row — places children side by side:

retui.Box(
    retui.Props{Direction: retui.Row, Gap: 2},
    retui.NewStyle(),
    retui.Text("Left", retui.NewStyle()),
    retui.Text("Right", retui.NewStyle()),
)
Left  Right

retui.Column — stacks children vertically:

retui.Box(
    retui.Props{Direction: retui.Column},
    retui.NewStyle(),
    retui.Text("One", retui.NewStyle()),
    retui.Text("Two", retui.NewStyle()),
    retui.Text("Three", retui.NewStyle()),
)
One
Two
Three

You can also nest boxes — a Row-direction Box containing Column-direction boxes, or vice versa — to build complex screens without calculating positions yourself. Props also supports Gap, Padding, Align, Justify, and Width/Height sizing (Fixed, Grow, Fit) for finer control.


7. Keyboard Focus

Terminal applications are usually controlled entirely by keyboard. RetUI keeps track of which component is currently focused, so navigation "just works."

Example — a form:

Name:  [Subha      ]
Email: [            ]

Pressing Tab moves focus to the next field:

Name:  [Subha      ]
Email: [user@mail.com]

RetUI exposes this through functions like retui.SetFocus, retui.CurrentFocus, retui.IsFocused, and retui.SetFocusOrder — most components handle focus styling automatically once you tell RetUI the order fields should follow.


8. Reusable Components

Once you build a component, you can reuse it anywhere in your app.

Instead of repeating this every time you need a labeled section:

retui.Box(
    retui.Props{Direction: retui.Column},
    retui.NewStyle().Bold(true),
    retui.Text("User", retui.NewStyle().Bold(true)),
)

Wrap it in a function once:

func UserPanel() retui.Element {
    return retui.Box(
        retui.Props{Direction: retui.Column},
        retui.NewStyle(),
        retui.Text("User", retui.NewStyle().Bold(true)),
    )
}

And reuse it wherever you need it:

func App() retui.Element {
    return retui.Box(
        retui.Props{Direction: retui.Column, Gap: 1},
        retui.NewStyle(),
        UserPanel(),
        UserPanel(),
    )
}

Reusable components keep applications easier to build, test, and maintain as they grow.


Summary

You only need to remember a few ideas to start building with RetUI:

  • Everything is a component — a function that returns an Element.
  • Box is the core layout primitive — components nest inside boxes, and boxes nest inside boxes.
  • State changes automatically update the screen — no manual redraw logic.
  • Hooks (UseState, UseStateKeyed, UseEffect, UseContext) manage state and behavior.
  • Direction: retui.Row or retui.Column on a Box controls where children appear.
  • Focus is tracked by RetUI and driven by functions like SetFocus and SetFocusOrder.
  • Small, reusable components are easier to maintain than one large function.

That's it! Once these click, the rest of the RetUI documentation will feel much more natural — everything else is just more components, more hooks, and more Box layouts built on top of these same ideas.

Clone this wiki locally