> ## Documentation Index
> Fetch the complete documentation index at: https://kawax.biz/llms.txt
> Use this file to discover all available pages before exploring further.

# Laravel Prompts

> Add beautiful, interactive CLI forms to your Artisan commands using the laravel/prompts package. Covers text input, selection, search, autocomplete, task logging, streaming output, and more.

## Introduction

[Laravel Prompts](https://github.com/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](/en/artisan), but it can be used in any command-line PHP project.

<Info>
  Laravel Prompts supports macOS, Linux, and Windows with WSL. In unsupported environments it falls back automatically to simpler input methods.
</Info>

## Installation

Laravel Prompts ships with Laravel and requires no additional installation.

To use it in a standalone PHP project, install via Composer:

```shell theme={null}
composer require laravel/prompts
```

## Available prompt functions

### text — free text input

`text()` prompts the user for a string and returns the value.

```php theme={null}
use function Laravel\Prompts\text;

$name = text('What is your name?');
```

Add a placeholder, default value, and hint:

```php theme={null}
$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:

```php theme={null}
$name = text(
    label: 'What is your name?',
    required: 'Your name is required.'
);
```

Add custom validation logic with a closure:

```php theme={null}
$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:

```php theme={null}
$name = text(
    label: 'What is your name?',
    validate: ['name' => 'required|max:255|unique:users']
);
```

### textarea — multi-line input

`textarea()` accepts multi-line input.

```php theme={null}
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.

```php theme={null}
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.

```php theme={null}
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`.

```php theme={null}
use function Laravel\Prompts\confirm;

$confirmed = confirm('Do you accept the terms?');
```

Customize the default value and button labels:

```php theme={null}
$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.

```php theme={null}
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:

```php theme={null}
$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).

```php theme={null}
$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.

```php theme={null}
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.

```php theme={null}
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.

```php theme={null}
$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 — dynamic search

`search()` filters a list in real time as the user types.

```php theme={null}
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.

```php theme={null}
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.

```php theme={null}
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.

```php theme={null}
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:

```php theme={null}
$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:

```php theme={null}
$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.

```php theme={null}
$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.

```php theme={null}
$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.

```php theme={null}
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.

```php theme={null}
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!');
```

## Callouts

`callout()` displays a boxed message with a label and content — ideal for surfacing important information such as deployment summaries, error details, or status updates.

```php theme={null}
use function Laravel\Prompts\callout;

callout(
    label: 'Environment Configured',
    content: 'Your application is running in production mode with 4 workers.',
);
```

Pass `'warning'` or `'error'` as the `type` argument to change the visual style.

```php theme={null}
callout(
    label: 'Deprecation Notice',
    content: 'The `--prefer-stable` flag will be removed in v4.0. Use `--stability=stable` instead.',
    type: 'warning',
);

callout(
    label: 'Database Connection Failed',
    content: 'Could not connect to MySQL on 127.0.0.1:3306.',
    type: 'error',
);
```

The `info` argument adds a footer line — useful for displaying metadata like IDs or timestamps.

```php theme={null}
callout(
    label: 'Deployment Summary',
    content: 'Your application was deployed to production.',
    info: 'deploy-id: d4f8a2c',
);
```

### Rich content

Instead of a string, pass an array to build rich, structured callouts. The `Element` class provides factory methods for headings, bulleted lists, numbered lists, and key-value lists.

```php theme={null}
use Laravel\Prompts\Elements\Element;
use function Laravel\Prompts\callout;

callout('Deployment Summary', [
    'Your application was deployed to production at 2024-03-15 14:32 UTC.',
    Element::heading('What Changed'),
    Element::bulletedList([
        'Migrated 3 pending database migrations',
        'Cleared and rebuilt route cache',
        'Restarted 4 queue workers',
    ]),
    Element::heading('Next Steps'),
    Element::numberedList([
        'Verify the health check endpoint at /up',
        'Monitor error rates for the next 15 minutes',
        'Confirm background jobs are processing',
    ]),
]);
```

Use `Element::keyValueList` to display labeled data:

```php theme={null}
callout('Database Connection Failed', [
    'Could not connect to the database server.',
    Element::keyValueList([
        'Host'     => '127.0.0.1',
        'Port'     => '3306',
        'Database' => 'forge',
        'Status'   => 'Connection refused',
    ]),
], type: 'error');
```

The `Element::link` method creates a clickable hyperlink in terminals that support [OSC 8](https://gist.github.com/egmontkob/eb114294efbcd5adb1944c9f3cb5feda). You may provide a URL alone, or a URL with a custom label:

```php theme={null}
callout('Server Health Check', [
    'Multiple services are reporting degraded performance.',
    Element::heading('Affected Services'),
    'Look here: '.Element::link('https://example.com/health', 'Health Dashboard'),
    Element::link('https://example.com/health'),
]);
```

If no label is provided, the URL itself will be displayed as the link text.

## Tables

Display rows of data in a formatted table.

```php theme={null}
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.

```php theme={null}
use function Laravel\Prompts\spin;

$response = spin(
    message: 'Fetching response...',
    callback: fn () => Http::get('http://example.com')
);
```

<Warning>
  `spin()` requires the `pcntl` PHP extension. Without it, no spinner is shown but the callback still runs.
</Warning>

## Progress bar

`progress()` displays a progress bar while iterating over items.

```php theme={null}
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.

```php theme={null}
$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.

```php theme={null}
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.

<Warning>
  `task()` requires the `pcntl` PHP extension to animate the spinner. Without it, a static version of the task will appear instead.
</Warning>

### Logging lines

The `line` method writes a single log line to the scrolling output area:

```php theme={null}
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:

```php theme={null}
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:

```php theme={null}
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:

```php theme={null}
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`:

```php theme={null}
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.

```php theme={null}
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

```php theme={null}
use function Laravel\Prompts\title;

title('My Application');
```

Pass an empty string to reset the terminal title to its default:

```php theme={null}
title('');
```

### Clear the terminal

```php theme={null}
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()`.

```php theme={null}
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:

```php theme={null}
// 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', 'taylor@example.com'],
            ]
        )
        ->assertExitCode(0);
});
```

```php theme={null}
// 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', 'taylor@example.com']]
        )
        ->assertExitCode(0);
}
```

## Related pages

<Columns cols={2}>
  <Card title="Artisan console" icon="terminal" href="/en/artisan">
    Use Prompts inside Artisan commands
  </Card>
</Columns>


## Related topics

- [Laravel Chisel — Post-install Script Library for Starter Kits](/en/blog/chisel-introduction.md)
- [GitHub Copilot SDK for Laravel](/en/packages/laravel-copilot-sdk/index.md)
- [Console Tests](/en/console-tests.md)
- [Permission request](/en/packages/laravel-copilot-sdk/permission-request.md)
- [Streaming](/en/packages/laravel-copilot-sdk/streaming.md)
