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.
The textarea auto-expands as you type and resets after sending. Enter sends, Shift+Enter inserts a newline.
<x-ui::composer name="message" />
Populate the actions slot with x-ui::composer-action buttons. Each button accepts an icon, tooltip, variant, active, and badge props.
<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>
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.
<x-ui::composer
name="tweet"
placeholder="What's on your mind?"
:max-length="280"
/>
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
{{-- 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…" />
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!
// 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>
A wider, taller composer with a character limit and tool buttons — the typical pattern for AI assistant inputs.
// 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>
Use the prepend slot to render content above the textarea — perfect for reply previews, attached file chips, or thread context.
Reply-to indicator
Attached files
<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>
Pass :loading="true" to show a spinner on the send button and lock the entire composer while a request is in-flight.
<x-ui::composer
placeholder="Ask something…"
:loading="$isProcessing"
@composer-send.window="$wire.process($event.detail.message)"
/>