Skip to main content
A PHP library · MIT

A dependency-light PHP engine for interactive, keyboard-driven terminal forms. Declare the questions with a fluent builder; the engine renders a scrollable, themeable TUI - or collects the answers headlessly from JSON and environment variables.

composer require drevops/phptui
quick-start

Declare a form in PHP

Describe the questions with a fluent builder - text, choices, toggles and more - and call run(). Interactive on a terminal, non-interactive otherwise.

form.php
use DrevOps\PhpTui\Builder\Form;
use DrevOps\PhpTui\Builder\PanelBuilder;
use DrevOps\PhpTui\Tui;
$form = Form::create('Quick start')
->panel('order', 'New order', function (PanelBuilder $p): void {
$p->text('name', 'Order name')->required();
$p->select('fruit', 'Fruit')->default('banana')->options([
'apple' => 'Apple',
'banana' => 'Banana',
'cherry' => 'Cherry',
]);
$p->select('veg', 'Vegetables')->multiple()->default(['carrot'])->options([
'carrot' => 'Carrot',
'tomato' => 'Tomato',
'spinach' => 'Spinach',
]);
$p->number('quantity', 'Quantity')->min(1)->max(99)->default(6);
$p->confirm('organic', 'Organic only?')->default(FALSE);
});
// Interactive on a terminal, non-interactive otherwise.
$answers = (new Tui($form))->run();
INTERACTIVE

On a terminal

A scrollable, keyboard-driven TUI; fields group into sections that drill in to any depth, with a contextual key-hint footer and a ? help overlay.

UNATTENDED

Everywhere else

Supply the answers up front as a JSON payload and environment variables so it runs without prompting. Emits a JSON schema for agents.

features

Built for keyboard-driven forms

The engine stays generic. Your questions and handlers live in the consumer - it collects, you apply. Open any card for the code and a recording.

fields

One layer, every field type

Text, numbers, dates, single and multiple choice, fuzzy search, file browsing, reordering and gates.

Animated demo of the Calendar field

Calendar

A month calendar returning a normalized ISO YYYY-MM-DD; arrows move by day and week.

Animated demo of the Confirm field

Confirm

Yes/No toggle; arrows or Space switch, y/n set the choice directly, Enter accepts.

Animated demo of the File picker field

File picker

Browse the filesystem for a path, or several with ->multiple(); -> enters a directory, <- returns to its parent.

Animated demo of the Number field

Number

Integer entry accepted as an int, with optional min, max and step.

Animated demo of the Password field

Password

Text rendered as a mask everywhere; the accepted value stays plain for the consumer, and can be made revealable.

Animated demo of the Pause field

Pause

An acknowledgement gate; Enter or Space accepts. Unattended runs auto-acknowledge it.

Animated demo of the Rating field

Rating

A graded answer picked off a scale of points, collected as an int; arrows walk the scale and points may carry captions.

Animated demo of the Reorder field

Reorder

Rank a list by moving items; Space picks an item up, arrows carry it, Enter accepts.

Animated demo of the Search field

Search

Single choice with a visible filter line; typing fuzzy-matches and ranks the labels.

Animated demo of the Select field

Select

Single choice from a list; arrows move, Enter accepts, long lists page around the cursor.

Animated demo of the Suggest field

Suggest

Free text with autocomplete over a fixed option set; suggestions fuzzy-matched and ranked.

Animated demo of the Template field

Template

A fixed shape with named slots; Tab moves between them and the assembled string is collected alongside its parts.

Animated demo of the Text field

Text

Single-line input with a movable caret; type to insert, arrows move, Backspace deletes.

Animated demo of the Textarea field

Textarea

Multi-line input; Enter inserts a newline, Tab accepts, with an external-editor handoff.

Animated demo of the Toggle field

Toggle

An inline switch between two labelled values; arrows or Space flip, first letter sets it directly.