TAMBOUI(1)

NAME

tambouiA Java library for building modern terminal user interfaces.

SYNOPSIS

$https://github.com/tamboui/tamboui/releases

INFO

379 stars
31 forks
0 views

DESCRIPTION

A Java library for building modern terminal user interfaces.

README

TamboUI

Release Downloads Build Status Chat All Contributors

TamboUI Gradient Logo

A Java library for building modern terminal user interfaces.

TamboUI brings the TUI paradigms seen in things like Rust's ratatui or Go's bubbletea to the Java ecosystem.

TamboUI is pronounced like "tambouille" (\tɑ̃.buj) in French, or "tan-bouy".

It provides a comprehensive set of widgets and a layout system for building rich terminal applications with modern Java idioms.

Note: TamboUI is still experimental and under active development. APIs may/will change. Feedback, issues, and contributions are welcome!

Snapshots

Currently TamboUI is only available as snapshot builds. You can use the following Maven repository to access snapshot versions:

🚀 Maven
<repository>
    <id>ossrh-snapshots</id>
    <url>https://central.sonatype.com/repository/maven-snapshots/</url>
    <releases>
        <enabled>false</enabled>
    </releases>
    <snapshots>
        <enabled>true</enabled>
    </snapshots>
</repository>
🛠️ Gradle
repositories {
    maven {
        url = uri("https://central.sonatype.com/repository/maven-snapshots/")
        mavenContent {
            snapshotsOnly()
        }
    }
}
📦 JBang
//REPOS https://central.sonatype.com/repository/maven-snapshots/

NOTE: If you are using JBang 0.136 or higher you can use the shortcut // REPOS central-portal-snapshots

Key Features

  • Immediate-mode rendering - Redraw the entire UI each frame for simple state management
  • Intermediate buffer system - Widgets render to a buffer, enabling diff-based terminal updates
  • Constraint-based layout - Flexible layout system with percentage, fixed, ratio, and proportional sizing
  • Multiple backends - Cross-platform terminal support using JLine 3, Panama, Aesh, and more
  • High-level TUI framework - TuiRunner eliminates boilerplate with built-in event handling and Cascading Style Sheets (CSS) support
  • PicoCLI integration - Optional module for CLI argument parsing
  • GraalVM native image support - Compile to native executables for instant startup
  • Works everywhere - Core is Java 8+ compatible, but following patterns that works really well with modern Java idioms

Modules

ModuleDescription
tamboui-coreCore types: Buffer, Cell, Rect, Style, Layout, Text primitives
tamboui-widgetsAll widget implementations (see below)
tamboui-jlineJLine 3 terminal backend
tamboui-tuiHigh-level TUI framework with TuiRunner, event handling, and key helpers
tamboui-toolkitFluent DSL for declarative UI construction with components and focus management
tamboui-picocliOptional PicoCLI integration for CLI argument parsing
tamboui-core-assertjAssertJ assertions for things like Buffer comparison
demos/*Demo applications showcasing widgets and features

Requirements

  • Java 8 or later, Java 17+ highly recommended
  • Gradle 9.x

JFR tracing

TamboUI can emit JFR events for diagnostics and performance analysis when a recording is active.

jcmd <pid> JFR.start name=tamboui settings=profile duration=60s filename=tamboui.jfr

Event names:

  • dev.tamboui.terminal.draw (duration of Terminal.draw())
  • dev.tamboui.toolkit.route (duration of toolkit event routing)
  • dev.tamboui.toolkit.candidate
  • dev.tamboui.toolkit.focus.change
  • dev.tamboui.toolkit.focus.navigation
  • dev.tamboui.toolkit.drag.state
  • dev.tamboui.toolkit.global.handler

Quick Start

Using TuiRunner (Recommended)

The tamboui-tui module provides a high-level framework that eliminates boilerplate:

//DEPS dev.tamboui:tamboui-tui:LATEST
//DEPS dev.tamboui:tamboui-jline3-backend:LATEST

package dev.tamboui.demo;

import dev.tamboui.tui.TuiRunner; import dev.tamboui.tui.event.KeyEvent; import dev.tamboui.widgets.paragraph.Paragraph; import dev.tamboui.text.Text;

public class HelloWorldTuiDemo { public static void main(String[] args) throws Exception { try (var tui = TuiRunner.create()) { tui.run( (event, runner) -> switch (event) { case KeyEvent k when k.isQuit() -> { runner.quit(); yield false; } default -> false; }, frame -> { var paragraph = Paragraph.builder() .text(Text.from("Hello, TamboUI! Press 'q' to quit.")) .build(); frame.renderWidget(paragraph, frame.area()); } ); } } }

Save the above file to HelloWorld.java and you can run it as jbang HelloWorld.java

With Mouse and Animation

import dev.tamboui.tui.TuiConfig;
import dev.tamboui.tui.TuiRunner;
import java.time.Duration;

var config = TuiConfig.builder() .mouseCapture(true) .tickRate(Duration.ofMillis(16)) // ~60fps animation .build();

try (var tui = TuiRunner.create(config)) { tui.run( (event, runner) -> switch (event) { case KeyEvent k when Keys.isQuit(k) -> { runner.quit(); yield false; } case MouseEvent m -> { handleMouse(m); yield true; } case TickEvent t -> { updateAnimation(t); yield true; } default -> false; }, frame -> render(frame) ); }

With PicoCLI Integration

//DEPS dev.tamboui:tamboui-picocli:LATEST
//DEPS dev.tamboui:tamboui-jline3-backend:LATEST

import dev.tamboui.picocli.TuiCommand; import picocli.CommandLine; import picocli.CommandLine.Command; import picocli.CommandLine.Option;

@Command(name = "myapp", mixinStandardHelpOptions = true) public class MyApp extends TuiCommand {

@Option(names = {&quot;-t&quot;, &quot;--title&quot;}, description = &quot;Window title&quot;)
private final String title = &quot;My App&quot;;

@Override
protected void runTui(TuiRunner runner) throws Exception {
    runner.run(this::handleEvent, this::render);
}

public static void main(String[] args) {
    System.exit(new CommandLine(new MyApp()).execute(args));
}

}

Using the declarative Toolkit

The tamboui-toolkit module provides a fluent DSL giving you retained mode declarative UI construction:

//DEPS dev.tamboui:tamboui-toolkit:LATEST
//DEPS dev.tamboui:tamboui-jline3-backend:LATEST

import static dev.tamboui.toolkit.Toolkit.*; import dev.tamboui.toolkit.app.ToolkitApp; import dev.tamboui.toolkit.element.Element;

public class HelloDsl extends ToolkitApp {

@Override
protected Element render() {
    return panel(&quot;Hello&quot;,
        text(&quot;Welcome to TamboUI DSL!&quot;).bold().cyan(),
        spacer(),
        text(&quot;Press &#39;q&#39; to quit&quot;).dim()
    ).rounded();
}

public static void main(String[] args) throws Exception {
    new HelloDsl().run();
}

}

Toolkit Elements

ElementFactory MethodDescription
Texttext("Hello")Styled text content
Panelpanel("Title", ...)Bordered container with title
Rowrow(a, b, c)Horizontal layout
Columncolumn(a, b, c)Vertical layout
Spacerspacer()Flexible empty space
Gaugegauge(0.75)Progress bar
LineGaugelineGauge(50)Single-line progress indicator
Sparklinesparkline(1,2,3,4,5)Mini data chart
Listlist("A", "B", "C")Selectable list
Tabletable()Data table with rows/columns
Tabstabs("Home", "Settings")Tab bar
TextInputtextInput(state)Text input field
BarChartbarChart(10, 20, 30)Bar chart
Chartchart()Line/scatter plots
Canvascanvas()Drawing surface
Calendarcalendar()Monthly calendar
Scrollbarscrollbar()Scroll position indicator

Toolkit Examples

// Progress with color coding
gauge(0.75)
    .label("Loading...")
    .gaugeColor(Color.GREEN)
    .title("Progress")
    .rounded()

// Sparkline chart sparkline(cpuHistory) .color(Color.CYAN) .title("CPU Usage") .rounded()

// Selectable list list("Option 1", "Option 2", "Option 3") .state(listState) .highlightColor(Color.YELLOW) .title("Menu") .rounded()

// Tab bar tabs("Home", "Settings", "About") .selected(0) .highlightColor(Color.CYAN)

// Table with data table() .header("Name", "Age", "City") .row("Alice", "30", "NYC") .row("Bob", "25", "LA") .widths(Constraint.percentage(40), Constraint.length(10), Constraint.fill()) .title("Users") .rounded()

// Canvas drawing canvas(-10, 10, -10, 10) .paint(ctx -> { ctx.draw(new Circle(0, 0, 5, Color.RED)); ctx.draw(new Line(-5, -5, 5, 5, Color.GREEN)); }) .title("Drawing") .rounded()

Features

  • Static imports - text(), panel(), row(), column(), spacer(), and all widget factories
  • Fluent styling - .bold(), .cyan(), .onBlue(), .rounded(), .borderColor()
  • Layout constraints - .length(n), .percent(n), .fill(), .min(n), .max(n)
  • Automatic focus - Tab navigation, click-to-focus
  • Component events - Components handle their own key/mouse events via .onKeyEvent() and .onMouseEvent()
  • Drag support - .draggable() for movable elements

Immediate Mode API

For more control, use the terminal directly:

//DEPS dev.tamboui:tamboui-widgets:LATEST
//DEPS dev.tamboui:tamboui-jline3-backend:LATEST

import dev.tamboui.terminal.Backend; import dev.tamboui.terminal.BackendFactory; import dev.tamboui.terminal.Terminal;

try (var backend = BackendFactory.create()) { backend.enableRawMode(); backend.enterAlternateScreen();

var terminal = new Terminal&lt;&gt;(backend);
terminal.draw(frame -&gt; {
    // render widgets...
});

}

Building

Building the Project

./gradlew assemble

Running Tests

./gradlew test

Publishing to Local Maven Repository

Useful when using when you want to use the library in your own Maven or JBang project.

./gradlew publishToMavenLocal

Publishing to the build directory

This method is preferred to publishing to Maven local to see what will actually be published:

./gradlew publishAllPublicationsToBuildRepository

Then look into build/repo for the generated artifacts.

Running Demos

To run the demos, you can either run them on the JVM or compile them to a native executable.

Using jbang

JBang

If you have JBang installed you can list the local catalog:

jbang alias list .

And then pick one you want to run, i.e.:

jbang sparkline-demo

If your IDE supports JBang you can open the demo .java files and run them directly from your IDE too.

Bash

You can use the ./run-demo.sh script to run any demo directly without building/installing first. For example, to run the sparkline-demo:

./run-demo.sh sparkline-demo

To run it as a native executable:

./run-demo.sh sparkline-demo --native
JVM

To run a demo on the JVM, first install the distribution and then execute the generated script. For example, to run the sparkline-demo:

./gradlew :demos:sparkline-demo:installDist
./demos/sparkline-demo/build/install/sparkline-demo/bin/sparkline-demo
Native Image (requires GraalVM)

To run as a native executable:

./gradlew :demos:sparkline-demo:nativeCompile
./demos/sparkline-demo/build/native/nativeCompile/sparkline-demo

Replace sparkline-demo with the name of any other demo (e.g., basic-demo, tui-demo, toolkit-demo).

Widgets

All standard ratatui widgets are implemented:

WidgetTypeDescription
BlockStatelessContainer with borders, titles, and padding
ParagraphStatelessMulti-line text with wrapping and alignment
ListStatefulScrollable list with selection
TableStatefulGrid with rows, columns, and selection
TabsStatefulTab bar with selection
GaugeStatelessProgress bar with percentage
LineGaugeStatelessHorizontal line progress indicator
SparklineStatelessMini line chart for data series
BarChartStatelessVertical bar chart
ChartStatelessLine and scatter plots with axes
CanvasStatelessDrawing surface with shapes (braille/block characters)
CalendarStatelessMonthly calendar with date styling
ScrollbarStatefulVisual scroll position indicator
ClearStatelessClears an area (for widget layering)
TextInputStatefulSingle-line text input (TamboUI addition)

Demo Applications

DemoDescription
hello-world-demoMinimal Hello World using TuiRunner
basic-demoInteractive list with text input
tui-demoShowcases TuiRunner with keyboard, mouse, and animation
toolkit-demoWidget Playground showcasing DSL with draggable panels
jtop-demoSystem monitor (like "top") using the DSL
picocli-demoPicoCLI integration with CLI options
gauge-demoProgress bars and line gauges
table-demoTable widget with selection
tabs-demoTab navigation
scrollbar-demoScrollbar with content
sparkline-demoSparkline data visualization
barchart-demoBar chart widget
chart-demoLine and scatter charts
canvas-demoCanvas with shapes and braille drawing
calendar-demoMonthly calendar with events

Key Bindings (via Keys utility)

The Keys class provides helpers for common key patterns:

import static dev.tamboui.tui.Keys.*;

// Quit patterns isQuit(event) // q, Q, or Ctrl+C

// Vim-style navigation (also accepts arrow keys) isUp(event) // Up arrow or k/K isDown(event) // Down arrow or j/J isLeft(event) // Left arrow or h/H isRight(event) // Right arrow or l/L

// Page navigation isPageUp(event) // PageUp or Ctrl+U isPageDown(event) // PageDown or Ctrl+D isHome(event) // Home or g isEnd(event) // End or G

// Actions isSelect(event) // Enter or Space isEscape(event) // Escape isTab(event) // Tab isBackTab(event) // Shift+Tab

Contributors

Cédric Champeau
Cédric Champeau

🚇 ⚠️ 💻
Max Rydahl Andersen
Max Rydahl Andersen

🚇 ⚠️ 💻
Claus Ibsen
Claus Ibsen

💻
Andres Almiray
Andres Almiray

🚇
Łukasz Kapica
Łukasz Kapica

📖 🚇

Acknowledgments

This project started as a port of ratatui, an excellent Rust TUI library. We thank the ratatui maintainers and contributors for their work.

License

MIT License - see LICENSE for details.

SEE ALSO

clihub3/16/2026TAMBOUI(1)