← All 41 libraries

SugarPrompt

💬 SugarPrompt

Interactive forms — Note, Input, Confirm, Select, MultiSelect, Text, FilePicker, Date, Slider, Color

port of charmbracelet/huh forms wizards validation

SugarPrompt code coverage

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 (a deprecated alias of candy-fuzzy's SmithWatermanMatcher):
$matcher = new FuzzyMatcher();
$score = $matcher->score('js', 'JavaScript');                   // 3
$best  = $matcher->matchAll('py', ['Python', 'PHP', 'Ruby'])[0]; // MatchResult: Python, score 11

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, candidate): ?MatchResult / matchAll(query, candidates): list<MatchResult>One match, or ranked matches (score desc)
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.