laravel/prompts
Laravel Prompts adds beautiful, user-friendly interactive forms to PHP CLI apps and Artisan commands. It supports placeholder text, validation, and a browser-like input experience, making it easy to collect and validate user input in the terminal.
Installation:
composer require laravel/prompts
No additional configuration is required—it works out-of-the-box with Laravel Artisan commands or standalone CLI scripts.
First Use Case:
Replace basic Symfony\Component\Console\Question\Question with Prompt for richer UX:
use Laravel\Prompts\Prompt;
$name = Prompt::text('What is your name?');
$age = Prompt::number('How old are you?', min: 18, max: 120);
$confirm = Prompt::confirm('Agree to terms?', default: false);
Where to Look First:
src/Prompt.php (core class) for method signatures.tests/ for edge-case usage patterns.Sequential Forms:
Chain prompts into a multi-step workflow using Form:
use Laravel\Prompts\Form;
$result = Form::make()
->text('Name')
->password('Secret')
->select('Role', ['admin', 'user'])
->submit();
Conditional Logic:
Use Form::conditional() to skip steps or modify prompts dynamically:
Form::make()
->text('Username')
->conditional(
fn ($username) => $username === 'admin',
fn () => Prompt::password('Admin Password')
)
->submit();
Data Validation: Validate inputs with closures or regex:
$email = Prompt::text('Email', validator: fn ($email) =>
$email && filter_var($email, FILTER_VALIDATE_EMAIL)
);
Dynamic Options:
Populate select/multiselect from database or API:
$users = User::all()->pluck('name', 'id');
$selected = Prompt::multiselect('Users', $users, default: [1, 2]);
Progress Feedback:
Use Progress for long-running tasks:
Progress::start('Processing...', 100);
foreach ($items as $item) {
Progress::next();
// Process $item
}
Progress::finish();
Artisan Commands:
Replace $this->ask() with Prompt::text() for consistency:
$this->info('Welcome, ' . Prompt::text('Name'));
Non-Interactive Mode:
Pass --non-interactive to skip prompts (useful for CI/CD):
php artisan my:command --non-interactive
Custom Components:
Extend Prompt for domain-specific inputs (e.g., ColorPickerPrompt).
Default Values:
false/null defaults may behave unexpectedly in select/multiselect. Use default: null explicitly.php artisan my:command --non-interactive to catch silent failures.Validation Quirks:
validator closures must return true/false (not throw exceptions). Use try/catch if needed.Prompt::text('Password', validator: [
fn ($p) => strlen($p) >= 8,
fn ($p) => preg_match('/[A-Z]/', $p),
]);
Terminal Compatibility:
chcp 65001 in scripts for UTF-8 support.Prompt::fake():
Prompt::fake(['text' => 'test']);
Performance:
validator closures—cache results if possible.Prompt::hidden() for sensitive data to prevent terminal history leaks.Silent Failures: Enable debug mode to log prompt interactions:
Prompt::debug(true);
Stuck Prompts:
Press Ctrl+C to abort. Use Prompt::abortIf() to handle interruptions:
Prompt::abortIf(fn () => connection('mysql')->disconnected());
Custom Prompts:
Extend Laravel\Prompts\Prompt to add domain-specific logic:
class GitBranchPrompt extends Prompt {
public static function gitBranch(string $question = 'Branch?'): string {
$branches = shell_exec('git branch --format "%(refname:short)"');
return static::select($question, explode("\n", $branches));
}
}
Override Renderers:
Modify UI components (e.g., TableRenderer) by publishing assets:
php artisan vendor:publish --tag=prompts.styles
Non-English Localization:
Override translations in config/prompts.php:
'translations' => [
'required' => 'Campo obrigatório',
],
Reusable Forms: Store form definitions in config or services:
// config/prompts.php
'forms' => [
'user_creation' => [
'name', 'email', ['password', 'hidden' => true],
],
];
Progress Bars:
Use Progress::withBar() for custom styling:
Progress::withBar()
->width(50)
->format('[:bar] :percent%')
->start('Uploading...');
Multiline Inputs:
For JSON/YAML, use Prompt::textarea() with syntax highlighting:
$config = Prompt::textarea('Config', default: '{}');
Testing:
Use Prompt::fake() to mock interactions:
Prompt::fake(['select' => 'option2']);
$result = Prompt::select('Choose', ['option1', 'option2']);
$this->assertEquals('option2', $result);
```markdown
### Config Quirks
- **Non-Interactive Mode**:
Ensure `Prompt::nonInteractive()` is called early in CLI scripts to avoid mixed behavior.
- **Default Values in Forms**:
Defaults in `Form::make()` override per-prompt defaults. Order matters:
```php
Form::make()
->text('Name', default: 'Guest') // Overridden by form default
->default('User')
->submit();
default: null for "no selection" in select/multiselect to avoid false being treated as a valid choice.How can I help you explore Laravel packages today?