← All libraries

SugarPrompt

💬 SugarPrompt

Interactive forms — Note, Input, Confirm, Select, MultiSelect, Text, FilePicker

port of huh forms wizards validation

Form library built on SugarCraft + SugarBits. Multi-page Group wizards, six themes, per-field validators, conditional skip predicates. The form is itself a Model — drop it into a Program.

Install

composer require sugarcraft/sugar-prompt

Quickstart

use SugarCraft\Prompt\Form;
use SugarCraft\Prompt\Field\{Input, Confirm, Select, Note};
use SugarCraft\Prompt\Validator\{Required, Email, MinLength};
use SugarCraft\Prompt\Fuzzy\FuzzyMatcher;

$form = Form::new(
    Note::new('welcome')
        ->withTitle('Onboarding')
        ->withDescription('A few quick questions.'),
    Input::new('name')
        ->withTitle('Your name?')
        ->withPlaceholder('Ada Lovelace')
        ->withValidator(new Required())
        ->withValidator(new MinLength(2)),
    Input::new('email')
        ->withTitle('Email address')
        ->withPlaceholder('you@example.com')
        ->withValidator(new Required())
        ->withValidator(new Email()),
    Select::new('lang')
        ->withTitle('Favorite language?')
        ->withOptions('PHP', 'Go', 'Rust', 'Python')
        ->withFuzzySuggestions(['PHP', 'Go', 'Rust', 'Python', 'JavaScript', 'TypeScript']),
);
// $form is a SugarCraft Model — drop it into a Program.

// Async suggestions:
$form = Form::new(
    Input::new('repo')
        ->withTitle('Repository')
        ->withAsyncSuggestions(fn($q) => fetchRepos($q), 150),
);

// FuzzyMatcher API:
$matcher = new FuzzyMatcher();
$score = $matcher->score('js', 'JavaScript'); // 9
$matches = $matcher->match('py', ['Python', 'PHP', 'Ruby']); // [['Python', 8], ...]

What's in the box

Field typesNote, Input, Confirm, Select, MultiSelect, Text, FilePicker.
Validation->withValidate(fn($v) => …) — return null to pass, error string to block submit. Five built-in validators: Required, Email, MinLength, MaxLength, Pattern. Chain multiple with ->withValidator(new Validator()). Cross-field validation via Form::validateAll(): array<string,string> after submit. Enable error summary with Form::withErrorSummary(true) to show all errors at once.
Fuzzy suggestions->withFuzzySuggestions([...]) on Input and Select — Smith-Waterman scoring ranks candidates by match quality. Use FuzzyMatcher directly for programmatic scoring: $matcher->score($query, $candidate).
Async suggestions->withAsyncSuggestions(callable $fetcher, int $debounceMs = 150) on Input and Select — fetches suggestions asynchronously with a configurable debounce delay. The SuggestionsReadyMsg message is dispatched via the event loop when results are available.
MultiSelect vim keysj / k navigate, Space toggles selection — mirrors vim-style keybindings.
Select enum modeSelect::withEnum(\BackedEnum::class) coerces the selected value to the given enum type automatically.
Multi-page GroupsGroup::new() stacks Forms into a wizard. Conditional ->withSkipFn().
Six themesDefault, charm, dracula, base16, catppuccin, pink. Custom error summary slot via Theme::$errorSummary.
Tab navTab / Shift+Tab between fields, Enter on the last submits, Esc / Ctrl+C aborts.
Submit hook$form->getValue('name') after the Program ends — typed value retrieval.
Form-level KeyMapForm::keyMap($keymap) rebinds Next / Prev / Submit / Quit per form (mirrors huh #272).

Source & demos

Try the quickstart →

API

ClassMethodDescription
Formnew(...fields)Create a new form
FormgetValue(name)Get field value after submit
FormvalidateAll()Run all field validators, return [fieldKey => errorMessage]
FormwithErrorSummary(bool)Show all errors at once on submit failure
Inputnew(name)Create input field
InputwithFuzzySuggestions(list)Filter suggestions by fuzzy match score
InputwithAsyncSuggestions(callable, int = 150)Async suggestions with debounce
Confirmnew(name)Create confirm field
Selectnew(name)Create select field
SelectwithFuzzySuggestions(list)Filter options by fuzzy match score
SelectwithAsyncSuggestions(callable, int = 150)Async suggestions with debounce
SelectwithEnum(BackedEnum::class)Coerce selected value to enum type
MultiSelectnew(name)Create multi-select field (j/k nav, Space toggle)
Notenew(content)Create note field
Groupnew(...forms)Create wizard group
FuzzyMatcherscore(query, candidate)Smith-Waterman alignment score (int)
FuzzyMatchermatch(query, candidates)Ranked matches list<[string,int]>
ThemeerrorSummaryRenderable slot for custom error summary display

Demos.

VHS-recorded GIFs of every example shipped with the library. Regenerated automatically on every push that touches the source.

Multi-page form

Multi-page form

Wizard across multiple Groups.
Input

Input

Single-line text with validation.
Confirm

Confirm

Y/N boolean.
Select

Select

Single-choice list.
MultiSelect

MultiSelect

Toggle multiple options.
Text

Text

Multi-line text input.
Themes

Themes

All six form themes side-by-side.