app
Root shell and top-level routing, status, and dialog coordination.
v0.1
The application framework for Bubble Tea.
Stop rebuilding the same architectural layer every time you ship a terminal app. BentoTUI gives you routing, layouts, focus management, dialogs, and theming.
go get github.com/cloudboy-jh/bentotui Every Bubble Tea app needs multi-panel layouts, focus routing, page switching, modal dialogs, and status bars. BentoTUI packages these patterns into composable Go packages so your app code stays focused on what makes it unique.
The bento-box grid makes the package story recognizable at a glance.
Root shell and top-level routing, status, and dialog coordination.
Page registration, lazy creation, active page switching.
Fixed/flex split containers for horizontal and vertical composition.
Focus ring helper and focus cycling across components.
Modal manager and dialog message contracts.
Contextual status line and key help surface.
Bordered container for child content.
Theme presets and custom token options.
Full working snippet from the project README.
package main
import (
"fmt"
tea "charm.land/bubbletea/v2"
"github.com/cloudboy-jh/bentotui"
"github.com/cloudboy-jh/bentotui/core"
"github.com/cloudboy-jh/bentotui/layout"
"github.com/cloudboy-jh/bentotui/theme"
"github.com/cloudboy-jh/bentotui/ui/components/panel"
)
func main() {
m := bentotui.New(
bentotui.WithTheme(theme.Preset("catppuccin-mocha")),
bentotui.WithPages(
bentotui.Page("home", func() core.Page { return newHomePage() }),
),
bentotui.WithFooterBar(true),
)
p := tea.NewProgram(m)
if _, err := p.Run(); err != nil {
fmt.Printf("run failed: %v\n", err)
}
}
type homePage struct {
root *layout.Split
width int
height int
}
func newHomePage() *homePage {
sidebar := panel.New(panel.Title("Sidebar"), panel.Content(staticText("Sessions\nFiles")))
main := panel.New(panel.Title("Main"), panel.Content(staticText("Welcome to BentoTUI")))
root := layout.Horizontal(
layout.Fixed(30, sidebar),
layout.Flex(1, main),
)
return &homePage{root: root}
}
func (p *homePage) Init() tea.Cmd { return nil }
func (p *homePage) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
_, cmd := p.root.Update(msg)
return p, cmd
}
func (p *homePage) View() tea.View { return p.root.View() }
func (p *homePage) SetSize(w, h int) {
p.width = w
p.height = h
p.root.SetSize(w, h)
}
func (p *homePage) GetSize() (int, int) { return p.width, p.height }
func (p *homePage) Title() string { return "Home" }
type staticText string
func (s staticText) Init() tea.Cmd { return nil }
func (s staticText) Update(msg tea.Msg) (tea.Model, tea.Cmd) { return s, nil }
func (s staticText) View() tea.View { return tea.NewView(string(s)) }