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, filtering, smart search, inline editing, bulk actions, expandable rows, exports, and a programmatic form builder. Includes artisan scaffolding; supports Tailwind + DaisyUI.

View on GitHub
Deep Wiki
Context7

Getting Started

Minimal Steps

  1. Installation

    composer require mrcatz/datatable
    

    Add the required directives to your base layout (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 pre-configured columns, filters, and actions.

  4. Add a Route

    Route::get('/admin/products', \App\Livewire\Admin\Product\ProductPage::class);
    

First Use Case

  • Quick CRUD: Use the generated ProductPage to display, filter, and edit products inline.
  • Search & Filter: Leverage built-in search and filters (e.g., createSearch, createCheck) to narrow down records.
  • Inline Editing: Click any cell to edit values directly in the table.

Implementation Patterns

Core Workflows

  1. Column Definition Define columns in your Livewire component using chainable methods:

    public function configureColumns(): array
    {
        return [
            (new Column('name'))
                ->label('Product Name')
                ->sortable()
                ->searchable()
                ->editable(),
            (new Column('price'))
                ->label('Price ($)')
                ->sortable()
                ->format(fn($value) => '$' . number_format($value, 2)),
        ];
    }
    
  2. Filter Integration Add filters to your table:

    public function configureFilters(): array
    {
        return [
            (new Filter('category_id'))
                ->label('Category')
                ->type('select')
                ->options(Product::categories())
                ->default('electronics'),
            (new Filter('price'))
                ->label('Price Range')
                ->type('range')
                ->min(0)
                ->max(1000),
        ];
    }
    
  3. Inline Editing Enable inline editing for specific columns:

    (new Column('status'))
        ->label('Status')
        ->editable()
        ->validationRule('required|in:active,inactive,paused')
        ->validationMessage('Status must be active, inactive, or paused.');
    
  4. Bulk Actions Add bulk actions to the table toolbar:

    public function configureBulkActions(): array
    {
        return [
            (new BulkAction('delete'))
                ->label('Delete Selected')
                ->icon('trash')
                ->action(fn($ids) => Product::whereIn('id', $ids)->delete()),
        ];
    }
    
  5. Form Builder Use the form builder for add/edit modals:

    public function configureForm(): FormBuilder
    {
        return (new FormBuilder())
            ->addSection('Basic Info', [
                (new TextInput('name'))
                    ->label('Product Name')
                    ->required(),
                (new NumberInput('price'))
                    ->label('Price ($)')
                    ->min(0),
            ])
            ->addSection('Advanced', [
                (new SelectInput('category_id'))
                    ->label('Category')
                    ->options(Product::categories())
                    ->required(),
            ]);
    }
    
  6. Export Integration Enable exports (CSV/Excel/PDF) with optional dependencies:

    composer require maatwebsite/excel barryvdh/laravel-dompdf
    

    Configure exports in your component:

    use HasExport;
    
    class ProductPage extends LivewireComponent implements HasExport
    {
        // ...
    }
    

Integration Tips

  • Livewire Hooks: Use mount() to initialize data or updatedProperty() to react to changes.
  • Custom Queries: Override getDataQuery() to modify the base query:
    protected function getDataQuery(): Builder
    {
        return Product::query()->where('is_active', true);
    }
    
  • Theming: Customize DaisyUI themes or override Tailwind classes in your CSS.
  • Localization: Use Laravel's localization features for filter labels and messages.

Gotchas and Tips

Pitfalls

  1. Filter Callbacks

    • Issue: Callbacks that mutate the query builder in place (without returning it) will cause errors in filters or exports.
    • Fix: Ensure callbacks return the modified query builder:
      // Correct
      fn($query, $value) => $query->whereDate('created_at', $value),
      
      // Incorrect (silently fails)
      function ($query, $value) { $query->whereDate('created_at', $value); }
      
    • Export-Specific: The HasExport trait has its own filter application logic. Use the exportApplyBuilderCallback helper for consistency.
  2. Filter Height Mismatch

    • Issue: Date/date-range/check filters may render taller than select filters, causing alignment issues.
    • Fix: Ensure all filter widgets use consistent height classes (e.g., h-8 for inputs and buttons).
  3. Checkbox Alignment

    • Issue: Long labels in createCheck filters may misalign checkboxes.
    • Fix: Use items-start, leading-5, and mt-0.5 on checkboxes to maintain vertical alignment.
  4. Export Zero Rows

    • Issue: Check filters may silently export zero rows due to incorrect whereIn usage.
    • Fix: Override buildExportQuery to handle check filters explicitly:
      protected function buildExportQuery(): Builder
      {
          $query = $this->getDataQuery();
          // Handle check filters separately
          return $query;
      }
      
  5. Tailwind Scanning

    • Issue: Forgetting to add @source for vendor blades may break styles.
    • Fix: Always include:
      @source '../../vendor/mrcatz/**/*.blade.php';
      

Debugging Tips

  • Query Logging: Enable Laravel query logging to debug filter issues:
    \DB::enableQueryLog();
    // Run your code
    \DB::getQueryLog();
    
  • Livewire Logs: Use dd($this->data) or dump($this->filters) to inspect component state.
  • Browser DevTools: Inspect rendered HTML/CSS for alignment or styling issues.

Extension Points

  1. Custom Columns Extend the Column class to add custom logic:

    class CustomColumn extends Column
    {
        public function customMethod()
        {
            return $this->modify(fn($value) => strtoupper($value));
        }
    }
    
  2. Custom Filters Create reusable filter types by extending Filter:

    class CustomFilter extends Filter
    {
        public function apply(Builder $query): Builder
        {
            return $query->where('custom_field', $this->value);
        }
    }
    
  3. Form Builder Extensions Add custom input types:

    class CustomInput extends Input
    {
        public function render()
        {
            return '<input type="custom" value="' . $this->value . '">';
        }
    }
    
  4. Export Customization Override buildExportQuery or extend HasExport to add custom export logic:

    protected function buildExportQuery(): Builder
    {
        $query = parent::buildExportQuery();
        return $query->with(['relationship']);
    }
    
  5. Theming Overrides Override DaisyUI or Tailwind classes in your CSS:

    /* Override filter button height */
    .datatable-filter-button {
        @apply h-8;
    }
    

Pro Tips

  • Reusable Components: Create base Livewire components for common CRUD pages to reduce boilerplate.
  • Partial Updates: Use Livewire's wire:model.live for real-time filtering or sorting.
  • Performance: For large datasets, use cursor() or chunk() in getDataQuery().
  • Testing: Use Livewire's testing helpers to test component interactions:
    $this->livewire(ProductPage::class)
         ->assertSee('Product Name')
         ->call('deleteSelected', [1, 2, 3]);
    
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.
sayedenam/sayed-dashboard
milito/query-filter
apiboxsym/user-bundle
apiboxsym/health-check-bundle
jayeshmepani/jpl-moshier-ephemeris-php
elnasnato/laraliveui
labrodev/rest-sdk
sampaui/sampaui
babelqueue/php-sdk
facebook/capi-param-builder-php
babelqueue/symfony
hamzi/corewatch
minionfactory/raw-hydrator
hexters/coinpayment
rjcodes/rjcms
act-training/laravel-permissions-manager
alimarchal/laravel-chart-of-accounts
babenkoivan/elastic-scout-driver
mkwebdesign/filament-watchdog-v5
renatomarinho/laravel-page-speed