https://github.com/allisonhere/tideui
Themeable multi-pane terminal UI toolkit for Bubble Tea and Lipgloss applications.
https://github.com/allisonhere/tideui
accessibility bubble-tea bubbletea charmbracelet component-library golang golang-library layout-engine lipgloss terminal-ui themeable themes tui tui-framework ui-toolkit wcag
Last synced: 5 days ago
JSON representation
Themeable multi-pane terminal UI toolkit for Bubble Tea and Lipgloss applications.
- Host: GitHub
- URL: https://github.com/allisonhere/tideui
- Owner: allisonhere
- License: mit
- Created: 2026-05-25T20:17:33.000Z (about 2 months ago)
- Default Branch: main
- Last Pushed: 2026-06-15T19:42:24.000Z (about 1 month ago)
- Last Synced: 2026-06-26T20:05:38.927Z (22 days ago)
- Topics: accessibility, bubble-tea, bubbletea, charmbracelet, component-library, golang, golang-library, layout-engine, lipgloss, terminal-ui, themeable, themes, tui, tui-framework, ui-toolkit, wcag
- Language: Go
- Homepage:
- Size: 296 KB
- Stars: 1
- Watchers: 0
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- License: LICENSE
Awesome Lists containing this project
README
# tideui
**A themeable, multi-pane terminal UI toolkit for [Bubble Tea](https://github.com/charmbracelet/bubbletea) and [Lipgloss](https://github.com/charmbracelet/lipgloss).**
`tideui` renders application-provided content inside themed pane shells, status
bars, and overlays. It is deliberately *view-oriented*: your application keeps
its own Bubble Tea model, key routing, persistence, and viewport state — you
hand `tideui` strings and dimensions, and it returns a framed, themed view.

## Lineage
The three-pane layout, theme-preview workflow, and themed modal language began
in [Tide](https://github.com/allisonhere/tide), a terminal RSS reader, and were
refined in [TideMail](https://github.com/allisonhere/tidemail), a keyboard-first
email client. `tideui` packages those reusable primitives for any Bubble Tea
application.
## Install
```bash
go get github.com/allisonhere/tideui
```
## Features
- **Five layout modes** — `StackedRight`, `ThreeColumn`, `SidebarOnly`, `Tabbed`, and `Floating`, each with tunable ratios.
- **Nineteen built-in palettes** (Catppuccin, Nord, Dracula, Gruvbox, and more) with per-field background/foreground/accent overrides.
- **Themed chrome** — pane headers, status bars, centered modal overlays, and a ready-made theme picker.
- **List primitives** — single-line `Row` and multi-line `Block` with selected/muted states.
- **Per-pane scrolling** via `Pane.ScrollOffset` and the `PaneScroller` helper.
- **Density + accessibility** — compact/comfortable spacing and a VT52 ASCII mode.
- **Bounded output** — never exceeds the requested terminal dimensions, down to tiny windows.
- **Terminal background control** — exposes the escape sequences so the app, not the library, writes to the terminal.
## Quick start
```go
import "github.com/allisonhere/tideui"
theme, _ := tideui.ThemeByName("catppuccin-mocha")
renderer := tideui.NewRenderer(theme, tideui.StyleOptions{Density: tideui.Compact})
view := renderer.Render(tideui.Layout{
Width: 80, Height: 24, Mode: tideui.StackedRight,
Panes: [3]tideui.Pane{
{Title: "Mailboxes", Content: "Inbox\nArchive", Focused: true},
{Title: "Messages", Content: "Welcome to tideui"},
{Title: "Preview", Content: "Application-owned content."},
},
Status: &tideui.StatusBar{Left: "ready", Right: "? help"},
})
```
## Bubble Tea integration
`tideui` owns no model state. Track dimensions and theme in your own model and
build a renderer in `View`:
```go
func (m model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
if size, ok := msg.(tea.WindowSizeMsg); ok {
m.width, m.height = size.Width, size.Height
}
return m, nil
}
func (m model) View() string {
r := tideui.NewRenderer(m.theme, tideui.StyleOptions{Density: m.density})
return r.Render(tideui.Layout{
Width: m.width, Height: m.height, Mode: tideui.ThreeColumn,
Panes: m.panes(),
})
}
```
## Layout modes
| Mode | Description | Ratio fields |
|---|---|---|
| `StackedRight` | Pane 0 sidebar; panes 1 & 2 stacked on the right | `SidebarRatio`, `UpperRightRatio` |
| `ThreeColumn` | All three panes side by side | `ColumnRatios` |
| `SidebarOnly` | Pane 0 sidebar; pane 1 full-height main (pane 2 unused) | `SidebarRatio` |
| `Tabbed` | Tab bar on top; the focused pane fills the area below | — |
| `Floating` | Pane 0 as background; panes 1 & 2 as floating panels | `FloatWidthRatio`, `FloatHeightRatio` |
```go
layout.Mode = tideui.StackedRight
layout.SidebarRatio, layout.UpperRightRatio = 0.30, 0.45
layout.Mode, layout.ColumnRatios = tideui.ThreeColumn, [3]float64{2, 3, 5}
```
In `Tabbed` mode the first `Focused` pane selects the active tab (falling back to
pane 0). All ratio fields default to sensible values when left zero.
## Theming
```go
theme, ok := tideui.ThemeByName("nord") // false if unknown
for _, t := range tideui.BuiltinThemes { /* ... */ }
```
Override individual colors without forking a palette:
```go
theme = tideui.ThemeOverrides{
Accent: "#f5c2e7",
}.Apply(tideui.CatppuccinMocha)
```
`Theme.UsesASCII()` reports VT52 mode (ASCII-only glyphs) so callers can adapt.
`StyleOptions{Density: tideui.Comfortable}` adds spacing; `Compact` removes it.
## Rows and blocks
`RenderRow` draws a single-line list item; `RenderBlock` adds an optional
multi-line body (a `Block` with no `Body` is byte-identical to the matching
`Row`). Both support `Selected` and `Muted`:
```go
renderer.RenderRow(tideui.Row{Prefix: "* ", Text: "Inbox", Suffix: "12", Selected: true}, width)
renderer.RenderBlock(tideui.Block{
Prefix: "● ", Header: "alice", Meta: "10:02",
Body: "Multi-line body, indented to the header.",
}, width)
```
For fully custom pane content, use the exported `renderer.Styles` (e.g.
`DetailTitle`, `DetailMeta`, `DetailBody`).
## Scrollable panes
Set `Pane.ScrollOffset`, or let `PaneScroller` manage it:
```go
m.scroll.ScrollDown(1) // ScrollUp / ScrollToTop also available
m.scroll.ClampTo(total, visible) // optional; renderer clamps out-of-range anyway
pane.ScrollOffset = m.scroll.Offset()
```
`CanScrollDown(total, visible)` reports whether more content lies below.
## Theme picker
A drop-in modal for previewing and confirming themes:
```go
picker := tideui.NewThemePicker(tideui.ThemePickerOptions{InitialTheme: "nord"})
picker.Open("nord")
switch picker.Update(keyMsg) {
case tideui.ThemePickerConfirm:
m.theme = picker.ConfirmedTheme()
case tideui.ThemePickerCancel:
// preview reverted to the confirmed theme
}
overlay := picker.Modal(renderer, m.width, m.height) // assign to Layout.Modal
```
The picker previews live as you navigate and restores the confirmed theme on
cancel.
## Terminal background
`tideui` never writes to the terminal itself. To paint the terminal background
to match the theme, fetch the sequences and emit them from your program:
```go
set, reset := tideui.TerminalBackgroundSequences(theme)
```
## Design
Applications retain ownership of their model, commands, key routing,
persistence, and viewport state. `tideui` is purely presentational — it turns
content + dimensions + a theme into a bounded, framed string. The one exception
is the optional `ThemePicker`, which manages its own navigation once opened.
## License
MIT.