Skeleton is a Go library built on top of the Bubble Tea framework designed to simplify the development of multi-tab terminal user interface (TUI) applications.
Caution: This project is under active development and may have breaking changes for a while.
- Multi-tab Support: Easily create and manage multiple tabs in your terminal application, similar to browser tabs.
- Dynamic Widgets: Add and update widgets on the screen, such as battery status, time, or any other information.
- Simple Integration: Build complex TUI applications with a straightforward and modular approach.
- Customizable: You can customize every aspect of the tabs and widgets, including key bindings and appearance.
- Realtime Updates: Updates itself instantly every time the terminal is resized, appearance changes, widgets changes, content changes, etc.
- Responsive Design: Automatically adjusts the layout based on the terminal size.
Skeleton leverages Bubble Tea's architecture to provide a framework for multi-tab TUI applications. This tutorial assumes you have a working knowledge of Go and Bubble Tea.
For a complete example code, you can refer to the source code on GitHub.
First, you'll need to install Skeleton. Use the following command to get it:
go get github.com/termkit/skeleton
Let's walk through an example of how to use Skeleton to create a basic multi-tab application.
We'll start by defining a simple model for our tabs. Each tab will be represented by a tinyModel
struct:
package main
import (
"fmt"
"strings"
"github.com/termkit/skeleton"
"github.com/charmbracelet/bubbles/key"
tea "github.com/charmbracelet/bubbletea"
)
// -----------------------------------------------------------------------------
// Tiny Model
// The Tiny Model is a sub-model for the tabs. It's a simple model that just shows the title of the tab.
// tinyModel is a sub-model for the tabs
type tinyModel struct {
skeleton *skeleton.Skeleton
title string
}
// newTinyModel returns a new tinyModel
func newTinyModel(skeleton *skeleton.Skeleton, title string) *tinyModel {
return &tinyModel{
skeleton: skeleton,
title: title,
}
}
func (m tinyModel) Init() tea.Cmd {
return nil
}
func (m tinyModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
return m, nil
}
func (m tinyModel) View() string {
verticalCenter := m.skeleton.GetTerminalHeight()/2 - 3
requiredNewLines := strings.Repeat("\n", verticalCenter)
return fmt.Sprintf("%s%s | %d x %d", requiredNewLines, m.title, m.skeleton.GetTerminalWidth(), m.skeleton.GetTerminalHeight())
}
Initialize Skeleton, add pages, and configure widgets:
// -----------------------------------------------------------------------------
// Main Program
func main() {
s := skeleton.NewSkeleton()
// Add tabs (pages)
s.AddPage("first", "First Tab", newTinyModel(s, "First"))
s.AddPage("second", "Second Tab", newTinyModel(s, "Second"))
s.AddPage("third", "Third Tab", newTinyModel(s, "Third"))
// Set up key bindings ( Optional | Defaults: ctrl+left, ctrl+right )
//To switch next page
s.KeyMap.SwitchTabRight = key.NewBinding(
key.WithKeys("shift+right"))
// To switch previous page
s.KeyMap.SwitchTabLeft = key.NewBinding(
key.WithKeys("shift+left"))
// Add a widget to entire screen
s.AddWidget("battery", "Battery %92")
s.AddWidget("time", time.Now().Format("15:04:05"))
// Update the time widget every second
go func() {
time.Sleep(time.Second)
for {
s.UpdateWidgetValue("time", time.Now().Format("15:04:05"))
time.Sleep(time.Second)
}
}()
p := tea.NewProgram(s)
if err := p.Start(); err != nil {
panic(err)
}
}
-
Model Definition:
tinyModel
represents the content of each tab. It uses the Skeleton instance to query terminal dimensions and display information. -
Application Setup: The
main
function initializes Skeleton, adds pages, and sets up widgets. The time widget updates every second to reflect the current time.
Some programs that use Skeleton in production:
- gama: Manage your GitHub Actions from Terminal with great UI 🧪
For more detailed documentation and additional examples, please refer to the Wiki or the Documentation.
Contributions are what make the open source community such an amazing place to learn, inspire, and create. Any contributions you make are greatly appreciated.
Distributed under the GNU GENERAL PUBLIC LICENSE Version 3 or later. See LICENSE for more information.