Phara UI v2.x

Composer

A configurable message input with an auto-expanding textarea, action button slots, character limit, and a send button. Dispatches a composer-send window event — ideal for chat interfaces and AI prompts.

Basic

The textarea auto-expands as you type and resets after sending. Enter sends, Shift+Enter inserts a newline.

Blade
<x-ui::composer name="message" />
Action Buttons

Populate the actions slot with x-ui::composer-action buttons. Each button accepts an icon, tooltip, variant, active, and badge props.

Blade
<x-ui::composer name="message">
    <x-slot:actions>
        <x-ui::composer-action icon="paperclip"  tooltip="Attach file" />
        <x-ui::composer-action icon="face-smile" tooltip="Emoji" />
        <x-ui::composer-action icon="microphone" tooltip="Voice message" />
    </x-slot:actions>
</x-ui::composer>
Max Length

Set :max-length to show a live character counter. The counter turns yellow at 85% and red when exceeded; the send button is disabled until the user trims the message.

Blade
<x-ui::composer
    name="tweet"
    placeholder="What's on your mind?"
    :max-length="280"
/>
Send on Enter

Toggle how Enter behaves. When send-on-enter is false, only Cmd+Enter sends — useful for multi-line compositions.

send-on-enter = true (default)

send-on-enter = false

Blade
{{-- Enter sends, Shift+Enter for newline (default) --}}
<x-ui::composer :send-on-enter="true" placeholder="Enter to send…" />

{{-- Only Cmd/Ctrl+Enter sends (good for multi-line input) --}}
<x-ui::composer :send-on-enter="false" placeholder="Shift+Enter for newline, Cmd+Enter to send…" />
Chat Interface

Listen to the composer-send window event and pass $event.detail.message to a Livewire action. The composer clears automatically after sending.

No messages yet — say something!

PHP
// Livewire component
public array $chatLog = [];

public function sendChat(string $message): void
{
    $this->chatLog[] = ['role' => 'user',     'text' => $message];
    $this->chatLog[] = ['role' => 'assistant','text' => yourAI($message)];
}

// Template
@foreach($chatLog as $msg)
    <div :class="$msg['role'] === 'user' ? 'justify-end' : 'justify-start'" class="flex">
        <div>{{ $msg['text'] }}</div>
    </div>
@endforeach

<x-ui::composer
    placeholder="Message…"
    @composer-send.window="$wire.sendChat($event.detail.message)"
>
    <x-slot:actions>
        <x-ui::composer-action icon="paperclip" tooltip="Attach" />
    </x-slot:actions>
</x-ui::composer>
AI Prompt

A wider, taller composer with a character limit and tool buttons — the typical pattern for AI assistant inputs.

PHP
// Livewire component
public string $promptReply = '';

public function sendPrompt(string $prompt): void
{
    $this->promptReply = yourAI($prompt);
}

// Template
<x-ui::composer
    placeholder="Ask anything…"
    :send-on-enter="true"
    :max-length="4000"
    :max-rows="12"
    @composer-send.window="$wire.sendPrompt($event.detail.message)"
>
    <x-slot:actions>
        <x-ui::composer-action icon="paper-clip"   tooltip="Attach file" />
        <x-ui::composer-action icon="globe-alt"    tooltip="Search web" />
        <x-ui::composer-action icon="beaker"       tooltip="Advanced mode" />
    </x-slot:actions>
</x-ui::composer>
Prepend Slot

Use the prepend slot to render content above the textarea — perfect for reply previews, attached file chips, or thread context.

Reply-to indicator

Replying to Alice Johnson — "Hey, did you see the latest..."

Attached files

design.fig
notes.pdf
screenshot.png
Blade
<x-ui::composer name="reply" placeholder="Write a reply…">
    <x-slot:prepend>
        {{-- Reply-to preview, attached files, etc. --}}
        <div class="flex items-center gap-2 text-sm text-zinc-500">
            <x-ui::icon name="arrow-uturn-left" class="w-3.5 h-3.5" />
            Replying to <strong>Alice Johnson</strong>
        </div>
    </x-slot:prepend>
</x-ui::composer>
Loading State

Pass :loading="true" to show a spinner on the send button and lock the entire composer while a request is in-flight.

Blade
<x-ui::composer
    placeholder="Ask something…"
    :loading="$isProcessing"
    @composer-send.window="$wire.process($event.detail.message)"
/>