-
Notifications
You must be signed in to change notification settings - Fork 4
Core Concept
New to RetUI? You're in the right place.
There are only 8 ideas to learn. Once they click, everything else in RetUI will make sense. Let's go through them one at a time, with real, working code.
Think of a component as a little Lego brick. You snap bricks together to build bigger things.
In code, a component is just a Go function that returns a retui.Element. That's it.
func Greeting() retui.Element {
return retui.Text("Hello, World!", retui.NewStyle())
}
Want to use it? Just call it:
func App() retui.Element {
return Greeting()
}
π Takeaway: if a function returns retui.Element, it's a component. You'll write dozens of these.
Here's the part that makes RetUI powerful: components can contain other components.
The main container you'll use is Box. Think of Box as an invisible wrapper that arranges whatever you put inside 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()),
)
}
That's a Box holding two pieces of text, stacked vertically:
Welcome
Hello RetUI!
You can keep nesting boxes inside boxes, as deep as you need:
Box
βββ Box
β βββ Text
β βββ Text
βββ Text
π Takeaway: Box is your building container. Everything lives inside one.
Here's something nice: you never manually clear or redraw the screen.
When your app's data changes, RetUI notices and updates only the part of the screen that changed.
Before: Counter: 5
After: Counter: 6
Only the 6 gets touched. Nothing else flickers or reprints. This is what keeps terminal apps feeling instant.
π Takeaway: change your data, RetUI handles the screen.
"State" is just a fancy word for a value your component remembers and can update.
Without state, text is stuck forever:
retui.Text("Counter: 0", retui.NewStyle())
With state, it can change over time:
count, setCount := retui.UseState(0)
retui.Text(fmt.Sprintf("Counter: %d", count), retui.NewStyle())
-
countβ the current value -
setCountβ the function you call to change it
setCount(count + 1) // bumps the counter, screen updates automatically
import (
"fmt"
"github.com/subhasundardass/retui/retui"
)
func Counter() retui.Element {
count, setCount := retui.UseState(0)
// Give this component a focus slot so it can receive key presses
retui.SetFocusOrder([]string{"counter"})
if retui.CurrentFocus() == "" {
retui.SetFocus("counter")
}
if retui.IsFocused("counter") {
switch retui.CurrentKey.Code {
case retui.KeyUp, retui.KeyEnter, retui.KeySpace:
setCount(count + 1)
case retui.KeyDown:
setCount(count - 1)
}
}
return retui.Box(
retui.Props{Direction: retui.Column, Gap: 1},
retui.NewStyle(),
retui.Text(fmt.Sprintf("Counter: %d", count), retui.NewStyle()),
retui.Text("β / Space / Enter: +1 β: -1", retui.NewStyle().Foreground(retui.Hex("#888888"))),
)
}
Copy this into your app and run it β press the button, watch the number climb. That's state in action.
π Takeaway: UseState gives you a value + a way to change it. RetUI handles the rest.
"Hooks" sound intimidating, but they're just special functions that let a component hold onto information between renders.
You just met one β UseState. Here are all four:
| Hook | What it's for | Beginner analogy |
|---|---|---|
| UseState | Store a value that can change | A sticky note your component keeps updating |
| UseStateKeyed | Same, but for lists/trees where items can appear or disappear | A sticky note labeled with a name instead of a position |
| UseEffect | Run code when something changes (with optional cleanup) | "When X happens, do Y" |
| UseContext | Share a value with components deep inside, without passing it manually | A shared bulletin board everyone can read |
That's genuinely everything you need to start. Every other RetUI feature you'll learn later is just a variation on these same 8 ideas.