Forms
NewA composable, huh-style form: typed fields grouped into (optionally conditional) wizard pages, per-field validation with inline errors, and dynamic fields whose visibility and options depend on other fields' values. Key-based and immutable — a Form is a TeaModel you can embed, or run one-shot with form.run().
Install the package
Every component ships in the single dart_tui package.
$dart pub add dart_tui

final form = Form([
Group([
Field.input(
key: 'name',
title: 'Service name',
validate: (v) => v.contains(' ') ? 'no spaces allowed' : null,
),
Field.select(
key: 'runtime',
title: 'Runtime',
options: ['Dart', 'Go', 'Node'],
initial: 'Dart',
),
Field.confirm(key: 'deploy', title: 'Deploy now?', initial: true),
], title: 'Basics'),
Group([
Field.multiSelect(key: 'regions', title: 'Regions',
options: ['iad', 'fra', 'sfo']),
Field.note(title: 'Review', description: 'Press enter to submit.'),
], title: 'Deploy', hidden: (v) => v.get<bool>('deploy') != true),
]);
final values = await form.run(); // FormValues? — null if cancelled
final regions = values?.get<List<String>>('regions');Any field or
Group accepts a hidden predicate, and titles/options can be computed dynamically with titleFor and optionsFor — recomputed live as other fields change.Field types
| Property | Type | Description |
|---|---|---|
| Field.input / .password | — | Single-line text, optionally masked. |
| Field.text | — | Multi-line text (text area). |
| Field.file | — | File path via the file picker. |
| Field.select / .selectOf<T> | — | Single choice from options. |
| Field.multiSelect / .multiSelectOf<T> | — | Multiple choices from options. |
| Field.confirm | — | Yes/no boolean. |
| Field.note | — | Static, non-interactive information block. |