Weave Code
Code Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Datatable Laravel Package

mrcatz/datatable

Opinionated DataTable + CRUD framework for Laravel Livewire. Build admin pages fast with pagination, sorting, filters, smart search, inline editing, bulk actions, expandable rows, exports, and a programmatic form builder. Includes Artisan scaffolding.

View on GitHub
Deep Wiki
Context7

Getting Started

Minimal Steps to First Use

  1. Installation

    composer require mrcatz/datatable
    

    Add the required directives to your base layout (resources/views/layouts/app.blade.php):

    @include('mrcatz::components.ui.notification')
    @livewireScripts
    @stack('scripts')
    
  2. Tailwind Configuration Update resources/css/app.css to include:

    @source '../../vendor/mrcatz/**/*.blade.php';
    
  3. Generate a CRUD Page Scaffold a new admin page with:

    php artisan mrcatz:make Product --path=Admin
    

    This creates a Livewire component with a pre-configured DataTable.

  4. Add a Route

    Route::get('/admin/products', \App\Livewire\Admin\Product\ProductPage::class);
    
  5. First Interaction Visit /admin/products to see a fully functional CRUD interface with:

    • Pagination
    • Sorting
    • Search
    • Inline editing
    • Bulk actions

Where to Look First

  • Documentation for feature deep dives.
  • app/Livewire/Admin/Product/ProductPage.php to inspect the generated scaffold.
  • resources/views/livewire/admin/product/product-page.blade.php for Blade template structure.

Implementation Patterns

Core Workflows

1. Column Configuration

Define columns in the columns() method of your DataTable class:

public function columns(): array
{
    return [
        Column::make('id', 'ID')
            ->sortable()
            ->searchable(),
        Column::make('name', 'Name')
            ->editable()
            ->rules('required|max:255'),
        Column::make('price', 'Price')
            ->format(fn($value) => '$' . number_format($value, 2))
            ->sortable(),
    ];
}

2. Filter Integration

Add filters to your table:

public function filters(): array
{
    return [
        Filter::make('status')
            ->select([
                'active' => 'Active',
                'pending' => 'Pending',
                'archived' => 'Archived',
            ])
            ->default('active'),
        Filter::make('created_at')
            ->dateRange()
            ->label('Created Date'),
    ];
}

3. Inline Editing

Enable cell-level editing with validation:

Column::make('description', 'Description')
    ->editable()
    ->rules('nullable|max:1000')
    ->validationMessage('Description must be less than 1000 characters.')

4. Bulk Actions

Add bulk operations:

public function bulkActions(): array
{
    return [
        BulkAction::make('delete')
            ->label('Delete Selected')
            ->icon('trash')
            ->color('error')
            ->action(function (array $ids) {
                Product::whereIn('id', $ids)->delete();
                $this->emit('toast', 'Products deleted successfully!');
            }),
    ];
}

5. Form Builder Integration

Define forms programmatically:

public function form(): Form
{
    return Form::make()
        ->columns(2)
        ->section('Basic Information', function (Form\Section $section) {
            $section->fields([
                Text::make('name')
                    ->required()
                    ->label('Product Name'),
                Text::make('price')
                    ->type('number')
                    ->required(),
            ]);
        })
        ->section('Advanced Options', function (Form\Section $section) {
            $section->fields([
                Select::make('category_id')
                    ->options($this->categories())
                    ->label('Category'),
                Checkbox::make('is_featured')
                    ->label('Featured Product'),
            ]);
        });
}

6. Export Configuration

Set up exports (requires maatwebsite/excel and barryvdh/laravel-dompdf):

public function exports(): array
{
    return [
        Export::make('csv')
            ->label('CSV Export')
            ->icon('file-csv')
            ->action(function () {
                return $this->exportToCsv();
            }),
        Export::make('pdf')
            ->label('PDF Export')
            ->icon('file-pdf')
            ->action(function () {
                return $this->exportToPdf();
            }),
    ];
}

Integration Tips

Livewire Component Structure

  • DataTable Class: Extend MrCatzDataTables for core functionality.
  • Page Class: Extend MrCatzPage for UI composition (e.g., ProductPage).
  • Blade Template: Use @livewire('admin.product.product-page') to render.

Query Building

Leverage the query() method to customize data fetching:

protected function query(): Builder
{
    return Product::query()
        ->with(['category', 'supplier'])
        ->when($this->search, function ($query) {
            return $query->where('name', 'like', "%{$this->search}%")
                         ->orWhere('description', 'like', "%{$this->search}%");
        });
}

Conditional Logic

Use mount() for initialization logic:

public function mount()
{
    $this->authorize('view', Product::class);
    $this->with(['categories' => Category::all()]);
}

Theming

Customize DaisyUI colors in tailwind.config.js:

module.exports = {
    daisyui: {
        themes: [
            {
                mytheme: {
                    'primary': '#3b82f6',
                    'secondary': '#374151',
                    // ...
                },
            },
        ],
    },
};

API-Driven Tables

For remote data, override getData():

public function getData(): array
{
    $response = Http::get('https://api.example.com/products');
    return $response->json()['data'];
}

Gotchas and Tips

Common Pitfalls

1. Missing Layout Directives

  • Symptom: DataTable renders but lacks styling, modals don’t work, or toasts fail.
  • Fix: Ensure @include('mrcatz::components.ui.notification'), @livewireScripts, and @stack('scripts') are in your base layout.

2. Tailwind Scanning Issue

  • Symptom: Styling appears broken or missing.
  • Fix: Verify @source '../../vendor/mrcatz/**/*.blade.php' is in app.css and Tailwind is configured to scan these files.

3. Callback Filter Crashes

  • Symptom: TypeError when using callback filters (e.g., createDateWithCallback).
  • Fix: Ensure callbacks return the modified query builder:
    // Bad (returns void/null)
    function ($query, $value) { $query->whereDate('foo', $value); }
    
    // Good (returns builder)
    function ($query, $value) { return $query->whereDate('foo', $value); }
    
    Workaround: Use the updated applyBuilderCallback helper (v1.29.28+).

4. Export Filter Mismatch

  • Symptom: Exports return 0 rows despite visible data.
  • Fix: Check for whereIn/whereNotIn conditions in filters. Use the check export branch explicitly:
    HasExport::buildExportQuery()->applyCheckFilter($filter, $activeValue);
    

5. Checkbox Filter Height

  • Symptom: Jagged baselines in filter toolbars with mixed filter types.
  • Fix: Ensure all filter widgets use h-8 (e.g., add h-8 to date inputs and adjust popover triggers).

6. Inline Editing Validation

  • Symptom: Edits save without validation feedback.
  • Fix: Add ->validationMessage() to columns and ensure rules are properly defined:
    Column::make('email')
        ->editable()
        ->rules('required|email')
        ->validationMessage('Please enter a valid email address.');
    

7. Meilisearch Beta Quirks

  • Symptom: Search results behave unexpectedly.
  • Fix: Verify Meilisearch is properly configured and indices are synced. Use the searchable()->meilisearch() modifier:
    Column::make('name')->searchable()->meilisearch();
    

Debugging Tips

Log Query Building

Override getQuery() to log SQL:

protected function getQuery(): Builder
{
    $query = Product::query();
    \Log::debug($query->toSql(), $query->getBindings());
    return $query;
}

Inspect Filter Values

Dump filter states in updated():

public function updated($propertyName)
{
    \Log::info('Filters:', $this->filters);
}

Check Export Queries

Log the export query before execution:

public function exportToC
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
terminal42/code-quality-tools
codifyo/ts-generator-bundle
andydefer/laravel-cluster
testo/fiber
mintobit/jobqueue
a4sex/maintenance-bundle
a4sex/entity-date-update
a4sex/client-identifier
a4sex/base-utilites
a4sex/key-value-storage
a4sex/micro-status
chilldev/dependency-injection-extra
datinglibre/datinglibre-app-api
biberltd/corebundle
bricre/symfony-bundle-test
biberltd/logbundle
dominium/http-adapter-bundle
dominium/google-analytics
a4sex/auto-clean-entity
christhompsontldr/laravel-inky