LC

lc:generate-table

Generator tool that creates standardized data table components following your project's specific Livewire and Blade conventions.

Install

mkdir -p .claude/skills/lc-generate-table && curl -L -o skill.zip "https://agentskills.codes/api/skills/download/19560" && unzip -o skill.zip -d .claude/skills/lc-generate-table && rm skill.zip

Installs to .claude/skills/lc-generate-table

Activation

This is the description your AI agent reads to decide when to run this skill — the better it matches your request, the more reliably it fires.

Generate a table component with filters, sorting, infinite scroll using the project's TableComponent base.
106 charsno explicit “when” trigger
Intermediate

Key capabilities

  • Generate Volt table components
  • Implement server-side filtering and sorting
  • Configure infinite scroll with x-intersect
  • Integrate row action dropdowns
  • Apply dark mode styling to UI elements

How it works

The skill inspects the project's existing TableComponent and model structure to generate a single-file Volt component that includes query logic, filtering, and UI templates.

Inputs & outputs

You give it
Model name
You get back
Volt component file with table logic and view

When to use lc:generate-table

  • Create a new table view for the User model
  • Generate an invoice list component with server-side sorting
  • Build a filterable data table for property listings
  • Standardize existing UI components using project patterns

About this skill

Subcommands

SubcommandDescription
<ModelName>Generate a table Volt component for the given model (e.g., Property, Client, User, Invoice)

Overview

This is a generator skill. It creates a complete table Volt component with filtering, sorting, infinite scroll, and row actions, following the project's established TableComponent pattern and UI conventions.

Instructions

Step 1: Understand the project's table patterns

Before generating, read existing table implementations to match conventions exactly:

  1. Read the base TableComponent class:

    • Search for class TableComponent using Grep
    • Understand: base properties, methods (loadMore, loadInitial, sortBy), traits used
  2. Read 1-2 existing table components for reference:

    • Use Glob: resources/views/livewire/**/*.blade.php
    • Look for components that extend TableComponent
    • Note the exact structure, column definitions, filter setup, and action dropdowns
  3. Read the table-related Blade components:

    • resources/views/components/tables/table.blade.php (or search for x-tables.table)
    • resources/views/components/tables/dropdown.blade.php (row action dropdown)
    • resources/views/components/filters.blade.php (or search for x-filters)

Step 2: Parse the argument and determine paths

Convert the ModelName to file paths:

  • Property -> resources/views/livewire/properties/index.blade.php
  • Client -> resources/views/livewire/clients/index.blade.php
  • Invoice -> resources/views/livewire/invoices/index.blade.php

Pluralize the model name for the directory. Use index.blade.php as the filename.

Step 3: Inspect the model

Read the model file to understand:

  • Table name and fillable fields
  • Available relationships (for eager loading)
  • Scopes that could be useful for filtering
  • Casts (dates, enums, booleans) that affect display
  • Soft deletes (if present, may need trash filter)
app/Models/ModelName.php

Step 4: Ask the user (if needed)

If the model has many fields, ask which columns to display in the table. If the context makes it clear, infer sensible defaults:

  • Show 4-7 columns maximum
  • Prioritize: name/title, status, key relationships, dates
  • Always include a date column (created_at or relevant date)

Step 5: Generate the Volt component

Create the file using Write tool.

Template structure:

<?php

use App\Models\ModelName;
use App\Http\Controllers\TableComponent;
use Livewire\Volt\Component;

new class extends TableComponent {

    public string $search = '';
    public string $sortField = 'created_at';
    public string $sortDirection = 'desc';
    public string $statusFilter = '';

    protected function query()
    {
        $query = ModelName::query()
            ->with(['relationship1', 'relationship2']);

        if ($this->search) {
            $query->where(function ($q) {
                $q->where('name', 'like', '%' . $this->search . '%')
                  ->orWhere('email', 'like', '%' . $this->search . '%');
            });
        }

        if ($this->statusFilter) {
            $query->where('status', $this->statusFilter);
        }

        return $query->orderBy($this->sortField, $this->sortDirection);
    }
}; ?>

<div>
    <x-filters>
        <x-filters.search wire:model.live.debounce.300ms="search" />

        <x-filters.select wire:model.live="statusFilter">
            <option value="">@text('all_statuses', 'All Statuses')</option>
            <option value="active">@text('active', 'Active')</option>
            <option value="inactive">@text('inactive', 'Inactive')</option>
        </x-filters.select>
    </x-filters>

    <x-tables.table
        :columns="[
            text('name', 'Name'),
            text('email', 'Email'),
            text('status', 'Status'),
            text('created_at', 'Created'),
        ]"
        :sortField="$sortField"
        :sortDirection="$sortDirection"
        :sortableColumns="['name', 'email', 'status', 'created_at']"
    >
        @forelse($this->items as $item)
            <tr wire:key="model-{{ $item->id }}">
                <td class="px-4 py-3 text-sm text-gray-900 dark:text-white">
                    {{ $item->name }}
                </td>
                <td class="px-4 py-3 text-sm text-gray-500 dark:text-gray-400">
                    {{ $item->email }}
                </td>
                <td class="px-4 py-3 text-sm">
                    <span class="px-2 py-1 text-xs font-medium rounded-full
                        {{ $item->status === 'active'
                            ? 'bg-green-100 text-green-800 dark:bg-green-900 dark:text-green-300'
                            : 'bg-gray-100 text-gray-800 dark:bg-gray-700 dark:text-gray-300' }}">
                        {{ $item->status }}
                    </span>
                </td>
                <td class="px-4 py-3 text-sm text-gray-500 dark:text-gray-400">
                    {{ $item->created_at->format('d/m/Y') }}
                </td>
                <td class="px-4 py-3 text-sm text-right">
                    <x-tables.dropdown>
                        <x-tables.dropdown-item
                            href="{{ route('models.show', $item) }}"
                            wire:navigate
                        >
                            @text('view', 'View')
                        </x-tables.dropdown-item>
                        <x-tables.dropdown-item
                            @click="$dispatch('open-edit-model', { id: {{ $item->id }} })"
                        >
                            @text('edit', 'Edit')
                        </x-tables.dropdown-item>
                        <x-tables.dropdown-item
                            @click="$dispatch('confirm-delete-model', { id: {{ $item->id }} })"
                            class="text-red-600 dark:text-red-400"
                        >
                            @text('delete', 'Delete')
                        </x-tables.dropdown-item>
                    </x-tables.dropdown>
                </td>
            </tr>
        @empty
            <tr>
                <td colspan="5" class="px-4 py-8 text-center text-gray-500 dark:text-gray-400">
                    @text('no_records_found', 'No records found')
                </td>
            </tr>
        @endforelse
    </x-tables.table>

    <div x-intersect="$wire.loadMore()">
    </div>
</div>

Step 6: Key conventions to follow

  1. NEVER include "Actions" in the columns array - The actions column is automatically handled by x-tables.dropdown. Only list data columns in the :columns array.

  2. ALWAYS use wire:key on each <tr> - Use a unique key like model-{{ $item->id }} to prevent DOM diffing bugs.

  3. Use @text() for all user-visible text - Column headers, status labels, filter labels, empty state messages. Defaults must be English.

  4. Infinite scroll with x-intersect - Place <div x-intersect="$wire.loadMore()"> after the table for automatic loading.

  5. Filters use wire:model.live.debounce.300ms for search and wire:model.live for selects.

  6. Eager load relationships - Always use ->with([...]) in the query to avoid N+1 problems.

  7. Dark mode support - Every visual element must have both light and dark variants.

  8. Volt single-file pattern - PHP at top, blade below, never separate class files.

  9. Model imports - Use use App\Models\ModelName; at the top.

  10. Sort defaults - Default sort by created_at desc unless another field makes more sense for the model.

Step 7: Adapt to the existing TableComponent

The generated component MUST match the exact interface of the project's TableComponent. After reading the base class in Step 1:

  • Match the exact method signatures (query(), loadMore(), loadInitial(), etc.)
  • Use the correct property names for items (might be $items, $this->items, or a computed property)
  • Follow the same pagination/infinite scroll mechanism
  • Match any trait usage

If the base class uses a different pattern than shown in the template above, adapt the template to match.

Step 8: Show usage instructions

After generating, display:

## Generated: resources/views/livewire/invoices/index.blade.php

### Add route in routes/app.php:
Route::get('/invoices', function () {
    return view('invoices.index');
})->name('invoices.index');

### Create the wrapper view (resources/views/invoices/index.blade.php):
<x-app-layout>
    <livewire:invoices.index />
</x-app-layout>

### Or use directly in another component:
<livewire:invoices.index />

### Columns displayed: name, email, status, created_at
### Filters: search (name, email), status
### Sorting: all columns sortable
### Actions: view, edit (opens modal), delete (opens confirmation)

Prerequisites

Existing TableComponent base classProject-specific Blade components

Limitations

  • Requires adherence to existing TableComponent interface
  • Limited to 4-7 columns for optimal display
  • Requires English defaults for user-visible text

How it compares

It automates the boilerplate creation of complex table views by strictly adhering to established project patterns and conventions rather than manual implementation.

Compared to similar skills

lc:generate-table side by side with the closest alternatives in the catalog.

SkillInstallsUpdatedSafetyDifficulty
lc:generate-table (this skill)03moNo flagsIntermediate
pennant-development24moNo flagsIntermediate
developing-with-turbo-streams14moNo flagsIntermediate
developing-with-turbo-frames14moNo flagsIntermediate

Try saying

Example prompts that trigger this skill in your AI assistant.

You might also like

pennant-development

laravel

Manages feature flags with Laravel Pennant. Activates when creating, checking, or toggling feature flags; showing or hiding features conditionally; implementing A/B testing; working with @feature directive; or when the user mentions feature flags, feature toggles, Pennant, conditional features, rollouts, or gradually enabling features.

29

developing-with-turbo-streams

hotwired-laravel

Basics of developing with Turbo Streams in web applications. Activate when working on projects that utilize Turbo Streams for enhancing user experience through real-time updates, dynamic content changes, and partial page updates without full reloads.

15

developing-with-turbo-frames

hotwired-laravel

Basics of developing with Turbo Frames in web applications. Activate when working on projects that utilize Turbo Frames for enhancing user experience through partial page updates, scoped navigation, and lazy loading of content within specific sections of a web page.

14

extending-shopper

shopperlabs

Provides patterns for extending Laravel Shopper with custom sidebar items, component overrides, event listeners, and domain features like stock, pricing, and media. Use when customizing Shopper behavior.

14

migration

JaguarJack

Generate database migration file for CatchAdmin module.

14

developing-with-turbo-basics

hotwired-laravel

Basics of developing with Turbo in web applications. Activate when working on projects that utilize Turbo for enhancing user experience through partial page updates, real-time interactions, and seamless navigation without full page reloads.

13

Search skills

Search the agent skills registry