Skip to main content

Documentation Index

Fetch the complete documentation index at: https://kawax.biz/llms.txt

Use this file to discover all available pages before exploring further.

Introduction

Laravel Prompts is a PHP package for adding beautiful and user-friendly forms to your command-line applications. It provides browser-like features such as placeholder text, validation, and styled output. Laravel Prompts is ideal for accepting user input inside Artisan console commands, but it can be used in any command-line PHP project.
Laravel Prompts supports macOS, Linux, and Windows with WSL. In unsupported environments it falls back automatically to simpler input methods.

Installation

Laravel Prompts ships with Laravel and requires no additional installation. To use it in a standalone PHP project, install via Composer:
composer require laravel/prompts

Available prompt functions

text — free text input

text() prompts the user for a string and returns the value.
use function Laravel\Prompts\text;

$name = text('What is your name?');
Add a placeholder, default value, and hint:
$name = text(
    label: 'What is your name?',
    placeholder: 'E.g. Taylor Otwell',
    default: $user?->name,
    hint: 'This will be displayed on your profile.'
);
Make the field required and customize the error message:
$name = text(
    label: 'What is your name?',
    required: 'Your name is required.'
);
Add custom validation logic with a closure:
$name = text(
    label: 'What is your name?',
    validate: fn (string $value) => match (true) {
        strlen($value) < 3  => 'The name must be at least 3 characters.',
        strlen($value) > 255 => 'The name must not exceed 255 characters.',
        default => null
    }
);
You can also pass Laravel validation rules as an array:
$name = text(
    label: 'What is your name?',
    validate: ['name' => 'required|max:255|unique:users']
);

textarea — multi-line input

textarea() accepts multi-line input.
use function Laravel\Prompts\textarea;

$story = textarea('Tell me a story.');

number — numeric input

number() accepts a numeric value. The user can also use arrow keys to increase or decrease the number.
use function Laravel\Prompts\number;

$copies = number(
    label: 'How many copies would you like?',
    default: 1,
    validate: ['copies' => 'required|integer|min:1|max:100']
);

password — masked input

password() behaves like text() but masks the typed characters.
use function Laravel\Prompts\password;

$password = password(
    label: 'What is your password?',
    placeholder: 'password',
    hint: 'Minimum 8 characters.',
    validate: fn (string $value) => strlen($value) < 8
        ? 'The password must be at least 8 characters.'
        : null
);

confirm — yes/no confirmation

confirm() asks a yes/no question and returns true or false.
use function Laravel\Prompts\confirm;

$confirmed = confirm('Do you accept the terms?');
Customize the default value and button labels:
$confirmed = confirm(
    label: 'Do you accept the terms?',
    default: false,
    yes: 'I accept',
    no: 'I decline',
    hint: 'The terms must be accepted to continue.'
);

select — single-choice list

select() presents a list and returns the chosen value.
use function Laravel\Prompts\select;

$role = select(
    label: 'What role should the user have?',
    options: ['Member', 'Contributor', 'Owner'],
    default: 'Owner'
);
Use an associative array to return a key instead of a display label:
$role = select(
    label: 'What role should the user have?',
    options: [
        'member'      => 'Member',
        'contributor' => 'Contributor',
        'owner'       => 'Owner',
    ],
    default: 'owner'
);
Control how many options are visible before scrolling with the scroll argument (default is 5).
$role = select(
    label: 'Which category would you like to assign?',
    options: Category::pluck('name', 'id'),
    scroll: 10
);

multiselect — multiple-choice list

multiselect() lets the user select one or more options. It returns an array.
use function Laravel\Prompts\multiselect;

$permissions = multiselect(
    label: 'What permissions should be assigned?',
    options: ['Read', 'Create', 'Update', 'Delete'],
    required: 'At least one permission must be selected.'
);

suggest — autocomplete input

suggest() shows suggestions while still accepting any input.
use function Laravel\Prompts\suggest;

$name = suggest(
    label: 'What is your name?',
    options: ['Taylor', 'Dayle']
);
Pass a closure to provide dynamic suggestions based on what the user has typed so far.
$name = suggest(
    label: 'What is your name?',
    options: fn (string $value) => collect(['Taylor', 'Tobi', 'Dries'])
        ->filter(fn ($name) => str_starts_with($name, $value))
        ->values()
        ->all()
);
search() filters a list in real time as the user types.
use function Laravel\Prompts\search;

$userId = search(
    label: 'Search for the user that should receive the mail',
    options: fn (string $value) => strlen($value) > 0
        ? User::whereLike('name', "%{$value}%")->pluck('name', 'id')->all()
        : []
);

multisearch — dynamic multi-select

multisearch() combines dynamic search with multiple selection.
use function Laravel\Prompts\multisearch;

$userIds = multisearch(
    label: 'Search for the users that should receive the mail',
    options: fn (string $value) => strlen($value) > 0
        ? User::whereLike('name', "%{$value}%")->pluck('name', 'id')->all()
        : []
);

pause — wait for keypress

pause() displays a message and waits for the user to press Enter.
use function Laravel\Prompts\pause;

pause('Press ENTER to continue.');

autocomplete — inline completion

autocomplete() provides inline ghost-text completion. Matching suggestions appear as users type and can be accepted by pressing Tab or the right arrow key. Unlike suggest(), the user is encouraged to choose from the provided options.
use function Laravel\Prompts\autocomplete;

$name = autocomplete(
    label: 'What is your name?',
    options: ['Taylor', 'Dayle', 'Jess', 'Nuno', 'Tim']
);
Add a placeholder, default value, and hint:
$name = autocomplete(
    label: 'What is your name?',
    options: ['Taylor', 'Dayle', 'Jess', 'Nuno', 'Tim'],
    placeholder: 'E.g. Taylor',
    default: $user?->name,
    hint: 'Use Tab to accept, up/down to cycle.'
);
Pass a closure to generate options dynamically based on what the user has typed:
$file = autocomplete(
    label: 'Which file?',
    options: fn (string $value) => collect($files)
        ->filter(fn ($file) => str_starts_with(strtolower($file), strtolower($value)))
        ->values()
        ->all(),
);

Validation

Every prompt function accepts a validate argument for custom validation logic. Return an error message string on failure, or null on success.
$name = text(
    label: 'What is your name?',
    validate: fn (string $value) => match (true) {
        strlen($value) < 3  => 'The name must be at least 3 characters.',
        strlen($value) > 255 => 'The name must not exceed 255 characters.',
        default => null
    }
);

Transforming input before validation

Use the transform argument to modify the input before validation runs.
$name = text(
    label: 'What is your name?',
    transform: fn (string $value) => trim($value),
    validate: fn (string $value) => match (true) {
        strlen($value) === 0 => 'The name must not be empty.',
        default => null
    }
);

Forms

form() groups multiple prompts so the user can go back and edit answers before submitting. If the user cancels, all prompts exit together.
use function Laravel\Prompts\form;

$responses = form()
    ->text('What is your name?', required: true, name: 'name')
    ->password('What is your password?', validate: ['password' => 'min:8'], name: 'password')
    ->confirm('Do you accept the terms?')
    ->submit();

$name      = $responses['name'];
$password  = $responses['password'];
$confirmed = $responses[2];

Informational messages

Display styled messages without prompting for input.
use function Laravel\Prompts\note;
use function Laravel\Prompts\info;
use function Laravel\Prompts\warning;
use function Laravel\Prompts\error;
use function Laravel\Prompts\alert;

note('Prepare for launch.');
info('User created successfully.');
warning('This action cannot be undone.');
error('Something went wrong.');
alert('Critical failure detected!');

Tables

Display rows of data in a formatted table.
use function Laravel\Prompts\table;

table(
    headers: ['Name', 'Email'],
    rows: User::all(['name', 'email'])->toArray()
);

Spin (loading indicator)

spin() displays a spinner while a callback runs.
use function Laravel\Prompts\spin;

$response = spin(
    message: 'Fetching response...',
    callback: fn () => Http::get('http://example.com')
);
spin() requires the pcntl PHP extension. Without it, no spinner is shown but the callback still runs.

Progress bar

progress() displays a progress bar while iterating over items.
use function Laravel\Prompts\progress;

$users = progress(
    label: 'Updating users',
    steps: User::all(),
    callback: fn ($user) => $this->performTask($user),
    hint: 'This may take some time.'
);
For manual control, use the start/advance/finish API.
$progress = progress(label: 'Uploading files', steps: count($files));

$progress->start();

foreach ($files as $file) {
    $this->uploadFile($file);
    $progress->advance();
}

$progress->finish();

Task

task() displays a labeled task with a spinner and a scrolling live output area while a given callback is executing. It is ideal for wrapping long-running processes such as dependency installation or deployment scripts, providing real-time visibility into what is happening.
use function Laravel\Prompts\task;

task(
    label: 'Installing dependencies',
    callback: function ($logger) {
        // Long-running process...
    }
);
The callback receives a Logger instance that you can use to display log lines and status messages in real time.
task() requires the pcntl PHP extension to animate the spinner. Without it, a static version of the task will appear instead.

Logging lines

The line method writes a single log line to the scrolling output area:
task(
    label: 'Installing dependencies',
    callback: function ($logger) {
        $logger->line('Resolving packages...');
        $logger->line('Downloading laravel/framework');
    }
);

Status messages

Use success, warning, and error to display stable highlighted messages above the scrolling log area:
task(
    label: 'Deploying application',
    callback: function ($logger) {
        $logger->line('Pulling latest changes...');
        $logger->success('Changes pulled!');

        $logger->line('Running migrations...');
        $logger->warning('No new migrations to run.');

        $logger->line('Clearing cache...');
        $logger->success('Cache cleared!');
    }
);

Updating the label

The label method updates the task’s label while it is running, and subLabel displays a dim line beneath it for ephemeral status messages. Pass an empty string to clear the sub-label:
task(
    label: 'Deploying',
    callback: function ($logger) {
        $logger->subLabel('Building assets...');
        // ...
        $logger->subLabel('Running migrations...');
        // ...
        $logger->subLabel('');
    },
    subLabel: 'Preparing...'
);

Streaming text

For processes that produce output incrementally — such as AI-generated responses — the partial method streams text word-by-word or chunk-by-chunk. Call commitPartial when the stream is complete:
task(
    label: 'Generating response...',
    callback: function ($logger) {
        foreach ($words as $word) {
            $logger->partial($word . ' ');
        }

        $logger->commitPartial();
    }
);

Customizing output limit and keeping the summary

By default the task displays up to 10 lines of scrolling output. Customize this with the limit argument. To keep the status messages on screen after the task finishes, pass keepSummary: true:
task(
    label: 'Deploying',
    callback: function ($logger) {
        $logger->success('Assets built');
        $logger->success('Migrations complete');
    },
    limit: 20,
    keepSummary: true,
);

Stream

stream() displays text that streams into the terminal incrementally — ideal for AI-generated content or any chunked output.
use function Laravel\Prompts\stream;

$stream = stream();

foreach ($words as $word) {
    $stream->append($word . ' ');
    usleep(25_000); // Simulate delay between chunks...
}

$stream->close();
The append method adds text to the stream with a gradual fade-in effect. Call close when all content has been streamed to finalize the output and restore the cursor.

Terminal utilities

Terminal title

use function Laravel\Prompts\title;

title('My Application');
Pass an empty string to reset the terminal title to its default:
title('');

Clear the terminal

use function Laravel\Prompts\clear;

clear();

Terminal considerations

Terminal width: Labels, options, and validation messages that exceed the terminal column width are automatically truncated. Aim for a maximum of 74 characters to safely support 80-column terminals. Terminal height: For prompts that accept the scroll argument, the configured value is automatically reduced to fit the terminal height, including space for a validation message.

Unsupported environments and fallbacks

In environments that don’t support the advanced rendering (such as Windows without WSL), Laravel Prompts automatically falls back to simpler input methods compatible with the host terminal. No code changes are required.

Testing

Fake prompt input in tests using Prompt::fake().
use Laravel\Prompts\Prompt;

Prompt::fake(['Taylor', true]);

$name      = text('What is your name?');
$confirmed = confirm('Do you accept the terms?');

Prompt::assertOutputContains('What is your name?');
When using Laravel’s Artisan test helpers, you can also assert against informational output functions:
// Pest
test('report generation', function () {
    $this->artisan('report:generate')
        ->expectsPromptsInfo('Welcome to the application!')
        ->expectsPromptsWarning('This action cannot be undone')
        ->expectsPromptsError('Something went wrong')
        ->expectsPromptsAlert('Important notice!')
        ->expectsPromptsTable(
            headers: ['Name', 'Email'],
            rows: [
                ['Taylor Otwell', '[email protected]'],
            ]
        )
        ->assertExitCode(0);
});
// PHPUnit
public function test_report_generation(): void
{
    $this->artisan('report:generate')
        ->expectsPromptsInfo('Welcome to the application!')
        ->expectsPromptsWarning('This action cannot be undone')
        ->expectsPromptsTable(
            headers: ['Name', 'Email'],
            rows: [['Taylor Otwell', '[email protected]']]
        )
        ->assertExitCode(0);
}

Artisan console

Use Prompts inside Artisan commands
Last modified on May 4, 2026