Skip to content

Getting Started

Edit this page

This guide walks you through building your first terminal UI application with Tui.

Creating a Tui

The Tui class is the entry point for every application. Create one, add widgets and run the event loop:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
use Symfony\Component\Tui\Tui;
use Symfony\Component\Tui\Widget\TextWidget;

use Symfony\Component\Tui\Event\InputEvent;
use Symfony\Component\Tui\Input\Keybindings;

$tui = new Tui();
$tui->add(new TextWidget('Hello, terminal!'));

$keys = new Keybindings(['quit' => ['ctrl+c']]);
$tui->addListener(static function (InputEvent $event) use ($tui, $keys): void {
    if ($keys->matches($event->getData(), 'quit')) {
        $tui->stop();
    }
});

$tui->run();

run() blocks until you call stop(). The Tui does not impose any default quit shortcut; listen for InputEvent to intercept keys and call stop() when appropriate.

The Tui takes ownership of the terminal: it hides the cursor, enables raw mode and restores everything when it stops.

Building the Widget Tree

The Tui manages a root ContainerWidget internally. Use add(), remove() and clear() to build the widget tree:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
use Symfony\Component\Tui\Widget\ContainerWidget;
use Symfony\Component\Tui\Widget\InputWidget;
use Symfony\Component\Tui\Widget\TextWidget;

$tui->add(new TextWidget('Enter your name:'));

$input = new InputWidget();
$tui->add($input);

// Remove a widget
$tui->remove($input);

// Remove all widgets
$tui->clear();

You can retrieve any widget by its id:

1
2
3
4
$input->setId('name-input');
$tui->add($input);

$widget = $tui->getById('name-input');

Setting Focus

Widgets that accept keyboard input (InputWidget, EditorWidget, SelectListWidget, etc.) implement FocusableInterface. Only the focused widget receives keyboard events. Set focus with setFocus():

1
$tui->setFocus($input);

When your application has multiple focusable widgets, see Focus Management for how to manage focus cycling.

Reacting to Events

Widgets dispatch events when the user interacts with them. The most common pattern is to register a callback on the widget directly:

1
2
3
4
5
6
7
8
9
10
use Symfony\Component\Tui\Event\SubmitEvent;

$input->onSubmit(function (SubmitEvent $event) {
    $value = $event->getValue();
    // process the submitted text
});

$input->onCancel(function () use ($tui) {
    $tui->stop();
});

For more advanced event handling (global listeners, filtering by source widget), see Events.

Styling the Root Container

The root container is matched by the :root pseudo-class selector, like in CSS. Style it through a stylesheet to control the global layout:

1
2
3
4
5
6
7
8
9
10
11
use Symfony\Component\Tui\Style\Style;
use Symfony\Component\Tui\Style\StyleSheet;
use Symfony\Component\Tui\Style\VerticalAlign;

$stylesheet = new StyleSheet();
$stylesheet->addRule(':root', new Style(
    gap: 1,
    verticalAlign: VerticalAlign::Bottom,
));

$tui = new Tui($stylesheet);

Pass the stylesheet to the constructor, or add it later with addStyleSheet(). See Styling for the full styling documentation.

Stopping the Tui

Call stop() to exit the event loop, restore the terminal and return control to the caller:

1
$tui->stop();

This is typically done inside an event callback:

1
2
3
$input->onSubmit(function () use ($tui) {
    $tui->stop();
});

After stop() returns, the terminal is back to its normal state. You can query widget values and write to the terminal:

1
2
3
4
5
6
$tui->run();

// After the loop exits
if ($input->wasSubmitted()) {
    echo 'You entered: '.$input->getValue()."\n";
}

A Complete Example

Putting it all together:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
use Symfony\Component\Tui\Event\InputEvent;
use Symfony\Component\Tui\Input\Keybindings;
use Symfony\Component\Tui\Style\Style;
use Symfony\Component\Tui\Style\StyleSheet;
use Symfony\Component\Tui\Tui;
use Symfony\Component\Tui\Widget\InputWidget;
use Symfony\Component\Tui\Widget\TextWidget;

$tui = new Tui(new StyleSheet([
    ':root' => new Style(gap: 1),
]));

$keys = new Keybindings(['quit' => ['ctrl+c']]);
$tui->addListener(static function (InputEvent $event) use ($tui, $keys): void {
    if ($keys->matches($event->getData(), 'quit')) {
        $tui->stop();
    }
});

$input = new InputWidget();
$input->setPrompt('Name: ');
$input->onSubmit(fn () => $tui->stop());

$tui->add(new TextWidget('Enter your name and press Enter:'));
$tui->add($input);
$tui->setFocus($input);

$tui->run();

if ($input->wasSubmitted()) {
    echo 'Hello, '.$input->getValue()."!\n";
}

Next Steps

  • Widgets for all available widgets.
  • Styling for colors, borders, padding and stylesheets.
  • Focus Management for focus cycling between multiple widgets.
  • Events for advanced event handling.
  • Keybindings for customizing keyboard shortcuts.
  • Tick Loop for async work and the tick callback.
This work, including the code samples, is licensed under a Creative Commons BY-SA 3.0 license.
TOC
    Version