From laraclaude
Generates a modal Volt component using the project's x-modal pattern with Livewire integration. Creates form or confirmation modals with validation and event dispatching.
How this skill is triggered — by the user, by Claude, or both
Slash command
/laraclaude:generate-modal [ModalName][ModalName]This skill is limited to the following tools:
The summary Claude sees in its skill listing — used to decide when to auto-load this skill
| Subcommand | Description |
| Subcommand | Description |
|---|---|
<ModalName> | Generate a modal Volt component with the given name (e.g., EditUser, ConfirmDelete, CreateInvoice) |
This is a generator skill. It creates a complete modal Volt component following the project's established patterns: <x-modal> component, Livewire/Volt single-file architecture, proper event dispatching, and form handling with validation.
Convert the ModalName to a blade file path:
EditUser -> resources/views/livewire/modals/edit-user.blade.phpCreateInvoice -> resources/views/livewire/modals/create-invoice.blade.phpConfirmDelete -> resources/views/livewire/modals/confirm-delete.blade.phpConvert PascalCase to kebab-case for the filename.
The modal ID will be derived from the filename: edit-user, create-invoice, confirm-delete.
resources/views/livewire/modals/<x-modal> component to understand available attributes:
resources/views/components/modal.blade.php or app/View/Components/Modal.phpsm, md, lg, xl, 2xl, 3xl, 7xl, 8xlresources/views/livewire/modals/*.blade.phpIf the user only provided a name, ask:
2xl)If the context makes the purpose clear, infer the answers and proceed.
Create the file at the determined path using the Write tool.
Template structure:
<?php
use App\Models\ModelName;
use Livewire\Volt\Component;
use Livewire\Attributes\On;
new class extends Component {
public ?int $modelId = null;
public string $fieldName = '';
// ... other form fields as public properties
#[On('open-modal-name')]
public function loadData(int $id): void
{
$model = ModelName::findOrFail($id);
$this->modelId = $model->id;
$this->fieldName = $model->field_name;
// ... populate form fields
$this->dispatch('open-modal', id: 'modal-id');
}
public function submit(): void
{
$this->validate([
'fieldName' => 'required|string|max:255',
// ... validation rules
]);
$model = ModelName::findOrFail($this->modelId);
$model->update([
'field_name' => $this->fieldName,
// ... other fields
]);
$this->dispatch('close-modal');
$this->dispatch('model-updated');
$this->reset();
}
public function resetForm(): void
{
$this->reset();
$this->resetValidation();
}
}; ?>
<x-modal id="modal-id" :title="text('modal_title', 'Modal Title')" size="2xl">
<div class="space-y-4">
<div>
<x-fields.text-input
wire:model="fieldName"
:label="text('field_name', 'Field Name')"
id="fieldName"
/>
</div>
{{-- Add more fields as needed --}}
</div>
<x-slot name="footer">
<button
type="button"
@click="$dispatch('close-modal')"
class="px-4 py-2 text-sm font-medium text-gray-700 bg-white border border-gray-300 rounded-lg hover:bg-gray-50 dark:bg-gray-700 dark:text-gray-300 dark:border-gray-600 dark:hover:bg-gray-600"
>
@text('cancel', 'Cancel')
</button>
<button
type="submit"
class="px-4 py-2 text-sm font-medium text-white bg-pink-600 rounded-lg hover:bg-pink-700 focus:ring-4 focus:ring-pink-300 dark:bg-pink-600 dark:hover:bg-pink-700 dark:focus:ring-pink-800"
>
@text('save', 'Save')
</button>
</x-slot>
</x-modal>
@text() for ALL user-visible text - Never hardcode strings. Default text must be in Englishx-fields.* components for form inputs - These already include @error directives. Do NOT add duplicate <x-input-error> components$dispatch('open-modal', { id: 'modal-id' }) from parent$dispatch('close-modal') or $this->dispatch('close-modal') from PHP<x-modal> component already wraps content in a form with wire:submit="submit"$this->reset() and $this->resetValidation() after successful submit$this->dispatch('model-updated'))use App\Models\ModelName; at the top, never inline \App\Models\ModelNameFor confirmation/delete modals, use a simpler pattern:
<?php
use App\Models\ModelName;
use Livewire\Volt\Component;
use Livewire\Attributes\On;
new class extends Component {
public ?int $modelId = null;
public string $modelName = '';
#[On('confirm-delete-model')]
public function setModel(int $id): void
{
$model = ModelName::findOrFail($id);
$this->modelId = $model->id;
$this->modelName = $model->name;
$this->dispatch('open-modal', id: 'confirm-delete-model');
}
public function submit(): void
{
$model = ModelName::findOrFail($this->modelId);
$model->delete();
$this->dispatch('close-modal');
$this->dispatch('model-deleted');
$this->reset();
}
}; ?>
<x-modal id="confirm-delete-model" :title="text('confirm_deletion', 'Confirm Deletion')" size="md">
<p class="text-gray-600 dark:text-gray-400">
@text('confirm_delete_message', 'Are you sure you want to delete')
<strong>{{ $modelName }}</strong>?
</p>
<x-slot name="footer">
<button
type="button"
@click="$dispatch('close-modal')"
class="px-4 py-2 text-sm font-medium text-gray-700 bg-white border border-gray-300 rounded-lg hover:bg-gray-50 dark:bg-gray-700 dark:text-gray-300 dark:border-gray-600 dark:hover:bg-gray-600"
>
@text('cancel', 'Cancel')
</button>
<button
type="submit"
class="px-4 py-2 text-sm font-medium text-white bg-red-600 rounded-lg hover:bg-red-700 focus:ring-4 focus:ring-red-300 dark:bg-red-600 dark:hover:bg-red-700 dark:focus:ring-red-800"
>
@text('delete', 'Delete')
</button>
</x-slot>
</x-modal>
After generating the file, show the user how to use the modal:
## Generated: resources/views/livewire/modals/edit-user.blade.php
### Include in parent view:
<livewire:modals.edit-user />
### Open from parent component (Blade/Alpine):
<button @click="$dispatch('open-edit-user', { id: {{ $user->id }} })">
Edit
</button>
### Open from parent component (Livewire PHP):
$this->dispatch('open-edit-user', id: $userId);
### Listen for updates in parent:
#[On('model-updated')]
public function refreshData(): void
{
// Refresh your data
}
npx claudepluginhub edulazaro/laraclaude --plugin laraclaudeGenerates Livewire Volt single-file components following project conventions. Studies existing patterns for consistent PHP, Tailwind, and Livewire usage.
Builds reactive UI with Livewire 4 on Laravel 13 using wire:model, actions, events, Volt, and Folio without writing JavaScript.
Provides best practices and patterns for Laravel Blade components including class-based, anonymous components, slots, attribute bags, and reusable UI like alerts and cards.