This is a PHP engine for building terminal user interfaces - the keyboard-driven forms that walk someone through a set of questions and hand the answers back to your code. You describe the questions in PHP with a fluent builder, drop in a handler class wherever a question needs real behaviour, and the engine does the rest: a scrollable, themeable TUI when there's a person at the keyboard, or a straight non-interactive read from a JSON payload when there isn't. It travels light, with barely any dependencies.
The engine deliberately knows nothing about the application it serves. It stays generic, your application-specific questions and handlers live in your code, and what happens to the answers afterwards is your job, not the TUI's. It collects; you apply.
That border is optional. Here's the same form without one, at normal spacing:
The full documentation - every widget, all the configuration, theming, key bindings and how the engine fits together - lives at phptui.dev.
- 🧭 Full-screen TUI - a scrollable, keyboard-driven form with a contextual key-hint footer and a
?help overlay - ⚡ Inline editing - a field's editor opens in place on the panel row (the widget's own view and keys), no separate screen; opt a field out to full-screen with
->standalone() - 🧩 Widgets - field types for text, numbers, dates, choices, file browsing, fuzzy search and gates
- 🏗️ Builder-driven - the form is declared in PHP with a fluent builder
- 🎛️ Interactive or unattended - answer the form by keyboard, or supply the answers up front as a JSON payload and environment variables so it runs without prompting
- 🔗 Derived values and 🔀 conditional fields that settle to a fixpoint
- 🔍 Discovery, ⚙️ declared behaviour and 📦 self-describing answers
- 🎨 Themes, ⌨️ key bindings and ✨ Unicode and ASCII display modes
- 🧪 Test harness - drive a form from scripted keystrokes and assert on the answers and rendered output
- 🌍 Translations - present chrome and questions in another language, falling back to English
composer require drevops/tuiDeclare a form with the fluent Form builder, then drive it through the Tui facade - the one class that wires up the engine, resolver, schema tools and TUI so you don't have to:
use DrevOps\Tui\Builder\Form;
use DrevOps\Tui\Builder\PanelBuilder;
use DrevOps\Tui\Tui;
$form = Form::create('My form')
->panel('general', 'General', fn(PanelBuilder $p) => $p->text('name', 'Your name')->required());
$tui = new Tui($form, ['App\\Handler']);
// Interactive on a terminal, non-interactive otherwise.
$answers = $tui->run();
// Or call a mode directly:
echo $tui->collect('{"name":"Ada"}')->toJson(); // non-interactive: JSON + environment
$answers = $tui->interact(); // interactive TUIRead the full guide at phptui.dev, and browse playground/ when you want complete, runnable examples to poke at.
There's a widget for most things you'd want to ask: text entry, numbers and dates, single and multiple choice, fuzzy search, filesystem browsing, and simple gates. Each one links to its full reference on phptui.dev, and every card below plays back the real interaction in whichever colour scheme - light or dark - your reader is using.
| Calendar A month calendar returning a normalized ISO YYYY-MM-DD; arrows move by day and week. |
|
| Confirm Yes/No toggle; arrows or Space switch, y/n set the choice directly, Enter accepts. |
|
| File picker Browse the filesystem for a single path; arrows move, → enters a directory and ← returns to its parent. |
|
| Multi file picker Like the file picker, but several paths accumulate as you browse; Space toggles the highlighted entry. |
|
| MultiSearch A multi-select whose filter query shows as a search line; typing fuzzy-matches and ranks, Space toggles matches. |
|
| MultiSelect Multiple choice from a checkbox list; Space toggles, typing narrows the list, select-all and deselect-all in one key. |
|
| Number Integer entry (digits with an optional leading minus) accepted as an int, with optional min, max and step. |
|
| Password Text rendered as a mask in the editor, the field row and the summary; the accepted value stays plain for the consumer, and can be made revealable. |
|
| Pause An acknowledgement gate; Enter or Space accepts. Unattended runs auto-acknowledge it, so it never blocks automation. |
|
| Reorder Rank a list by moving items into the order you want; Space picks an item up, arrows carry it through the list, Enter accepts. |
|
| Search Single choice with a visible filter line; typing fuzzy-matches and ranks the labels, exact and prefix matches leading. |
|
| Select Single choice from a list; arrows move, Enter accepts the highlighted option, long lists page around the cursor. |
|
| Suggest Free text with autocomplete over a fixed option set: as you type, suggestions are fuzzy-matched and ranked by relevance. |
|
| Text Single-line input with a movable caret; type to insert, arrows move, Backspace deletes, Enter accepts. |
|
| Textarea Multi-line input; Enter inserts a newline, arrows move between lines, Tab accepts, with an external-editor handoff. |
|
| Toggle An inline switch between two labelled values; arrows or Space flip, the first letter of each label sets it directly. |
composer install
composer lint
composer testSee the Contributing guide when you're ready to dig into the full development workflow.
This repository was created using the Scaffold project template