-
Notifications
You must be signed in to change notification settings - Fork 4
Components
RetUI includes a growing collection of ready-made components such as buttons, text inputs, checkboxes, lists, trees, and panels. These components help you build terminal applications quickly without creating every widget from scratch.
This guide explains how to use the built-in components and how to create your own.
Most interactive components use the same builder pattern.
components.SomeComponent().
ID("unique-id").
// Configure the component...
OnChange(func(id string, value T) {
// Handle changes
}).
Render()The pattern is always the same:
- Create the component with its constructor.
- Configure it using chained methods.
- Give it a unique
ID. - Finish with
.Render().
Without calling .Render(), the builder never becomes a retui.Element.
Buttons respond to keyboard interaction when focused.
components.Button().
ID("submit").
Label("Submit").
Style(retui.NewStyle().Background(retui.Blue)).
HoverStyle(retui.NewStyle().Background(retui.Cyan)).
OnClick(func(id string) {
retui.Debug("Button clicked:", id)
}).
Render()ID()Label()Style()HoverStyle()ActiveStyle()Prefix()Suffix()Focused()OnClick()
A single-line editable text field.
name, setName := retui.UseState("")
components.TextInput().
ID("name").
Value(name).
Placeholder("Enter your name").
Focused(retui.IsFocused("name")).
OnChange(func(id string, value string) {
setName(value)
}).
Render()Value()Placeholder()MinLength()MaxLength()Prefix()Suffix()Focused()OnChange()OnSubmit()
RetUI components are controlled components.
Your application owns the value.
Value(name)Whenever the user edits the field:
OnChange(func(id string, value string) {
setName(value)
})Your state changes, and RetUI automatically refreshes the screen.
A password input behaves like a text input but hides typed characters.
components.Password().
ID("password").
Value(password).
MaskChar("•").
ShowLastChar(true).
OnChange(func(id string, value string) {
setPassword(value)
}).
Render()Value()MaskChar()ShowLastChar()OnChange()
Accepts only numeric input.
price, setPrice := retui.UseState(0.0)
components.NumberInput().
ID("price").
Value(price).
Min(0).
Max(1000).
Step(0.5).
Decimals(2).
OnChange(func(id string, value float64) {
setPrice(value)
}).
Render()Value()Min()Max()Step()Decimals()ArrowStep()OnChange()
When ArrowStep(true) is enabled, the Up and Down arrow keys increase or decrease the value by the configured step.
A formatted date input with validation.
components.DateInput().
ID("dob").
Value(dob).
Format("DD/MM/YYYY").
Min("01/01/1900").
Max("31/12/2026").
OnChange(func(id string, value string) {
setDob(value)
}).
Render()Value()Format()Min()Max()OnChange()
A simple on/off option.
components.Checkbox().
ID("agree").
Checked(agree).
Label("I agree to the terms").
OnChange(func(id string, checked bool) {
setAgree(checked)
}).
Render()Checked()Label()OnChange()
Choose one option from a list.
components.SelectPicker().
ID("country").
Options([]string{
"USA",
"India",
"UK",
}).
Selected(selectedIndex).
OnChange(func(id string, index int, value string) {
setSelectedIndex(index)
}).
Render()Options()Selected()OnChange()OnSubmit()
OnChange() is called while moving through the options.
OnSubmit() is called when the selection is confirmed with Enter.
A scrollable list of selectable items.
components.List().
ID("results").
Items([]string{
"Apple",
"Banana",
"Cherry",
}).
Selected(selectedIndex).
OnSelect(func(id string, index int, value string) {
setSelectedIndex(index)
}).
Render()Items()Selected()OnSelect()
Unlike other components, Tree is not a builder.
It is a regular function because tree structures are naturally hierarchical.
var fileTree = []components.TreeNode{
{
ID: "src",
Label: "src",
Children: []components.TreeNode{
{
ID: "main.go",
Label: "main.go",
},
{
ID: "utils.go",
Label: "utils.go",
},
},
},
}
components.Tree(
"file-tree",
fileTree,
retui.IsFocused("file-tree"),
func(id string) {
retui.Debug("Selected:", id)
},
)Tree expansion and collapse are managed internally using UseStateKeyed().
You only provide the tree data and selection callback.
A bordered container with a title.
components.Panel(
"User Details",
50,
retui.Text("Name: Subha", retui.NewStyle()),
retui.Text("Role: Admin", retui.NewStyle()),
)Unlike builder components, Panel() immediately returns a retui.Element.
No .Render() call is needed.
Use retui.Box() when you don't need a border or title.
Every built-in component is simply a Go function returning a retui.Element.
You can build your own exactly the same way.
func UserCard(name string, role string) retui.Element {
return retui.Box(
retui.Props{
Direction: retui.Column,
Padding: [4]int{1, 2, 1, 2},
},
retui.NewStyle().Border(
retui.Border{
Top: true,
Right: true,
Bottom: true,
Left: true,
},
),
retui.Text(
name,
retui.NewStyle().Bold(true),
),
retui.Text(
role,
retui.NewStyle().
Foreground(retui.Hex("#888888")),
),
)
}Use it like any built-in component.
retui.Box(
retui.Props{
Direction: retui.Row,
Gap: 2,
},
retui.NewStyle(),
UserCard("Subha", "Admin"),
UserCard("Alex", "Editor"),
)Custom components can use hooks just like the built-in ones.
func Counter() retui.Element {
count, setCount := retui.UseState(0)
key, active := retui.UseFocusedKeySimple(
retui.IsFocused("counter"),
)
if active {
switch key.Code {
case retui.KeyUp:
setCount(count + 1)
case retui.KeyDown:
setCount(count - 1)
}
}
return retui.Box(
retui.Props{
Direction: retui.Column,
},
retui.NewStyle(),
retui.Text(
fmt.Sprintf("Counter: %d", count),
retui.NewStyle(),
),
)
}This example uses:
UseState()- Focus management
- Keyboard events
BoxText
These are the same building blocks used by RetUI's own components.
| Component | Constructor | Main Methods |
|---|---|---|
| Button | components.Button() |
Label(), OnClick()
|
| TextInput | components.TextInput() |
Value(), OnChange(), OnSubmit()
|
| Password | components.Password() |
Value(), MaskChar(), OnChange()
|
| NumberInput | components.NumberInput() |
Value(), Min(), Max(), Step(), OnChange()
|
| DateInput | components.DateInput() |
Value(), Format(), Min(), Max(), OnChange()
|
| Checkbox | components.Checkbox() |
Checked(), Label(), OnChange()
|
| SelectPicker | components.SelectPicker() |
Options(), Selected(), OnChange()
|
| List | components.List() |
Items(), Selected(), OnSelect()
|
| Tree | components.Tree() |
Function-based API |
| Panel | components.Panel() |
Function-based API |
Most interactive components follow this pattern:
components.Component().
ID("id").
// Configure...
Render()Only Tree and Panel are different—they are regular functions that return a retui.Element directly and do not require .Render().