| Install | |
|---|---|
composer require artflow-studio/table |
|
| Latest Version: | 1.5.5 |
| PHP: | * |
A production-ready, trait-based Laravel Livewire datatable component with automatic optimization, N+1 prevention, and 98% query reduction.
Version: 1.8.0 | Status: ✅ Production Ready | PHP: 8.2+ | Laravel: 12+ | Livewire: 4.2+ | Blaze: 1.0+ | Site: https://artflow.pk
ArtFlow Table is a trait-based Livewire component that builds powerful, performant datatables with:
#[Computed] caching - Livewire 4 native memoization, no manual hash logic@island(defer: true) keeps initial paint fastPerfect for: Admin panels, data management, reports, dashboards
composer require artflow-studio/table
That's it! Package auto-registers with Laravel. livewire/blaze is bundled as a dependency and activates automatically — no configuration needed.
Optional: Set
BLAZE_ENABLED=falsein your.envto disable Blaze's Blade compilation step.
@livewire('aftable', [
'model' => 'App\Models\Item',
'columns' => [
['key' => 'title', 'label' => 'Item Name'],
['key' => 'code', 'label' => 'Code'],
['key' => 'amount', 'label' => 'Amount'],
],
])
That's all you need! The table automatically:
@livewire('aftable', [
'model' => 'App\Models\Item',
'columns' => [
['key' => 'title', 'label' => 'Name'],
['key' => 'category_name', 'label' => 'Category', 'relation' => 'category:name'],
['key' => 'department_name', 'label' => 'Department', 'relation' => 'department:name'],
['key' => 'subitems_count', 'label' => 'Sub-items'],
],
])
System automatically:
category and department relationswithCount()| Metric | Result | Improvement |
|---|---|---|
| Database Queries | 1 query | 98% reduction (51 → 1) |
| Page Load Time | 150-200ms | 75-80% faster (800ms → 200ms) |
| Configuration Code | Minimal | 80% less than competitors |
| Memory Usage | Optimized | Handles 1M+ records |
Real Example: Displaying 50 products with categories, brands, and variant counts
['key' => 'title', 'label' => 'Item Name']
['key' => 'category_name', 'label' => 'Category', 'relation' => 'category:name']
['key' => 'subitems_count', 'label' => 'Sub-items']
_count suffix ✅withCount() for efficiency ✅[
'key' => 'actions',
'label' => '',
'actions' => [
['type' => 'button', 'label' => 'Edit', 'href' => '/items/{id}/edit'],
['type' => 'button', 'label' => 'Delete', 'href' => '/items/{id}', 'method' => 'DELETE'],
]
]
@livewire('aftable', [
'model' => 'App\Models\Item', # Eloquent model
'columns' => [...], # Column definitions
'records' => 50, # Items per page
'showSearch' => true, # Show search box
'showPagination' => true, # Show pagination
'showColumnVisibility' => true, # Show column toggles
'showExport' => true, # Show export button
'exportFormats' => ['csv', 'excel', 'pdf'], # Available export types
'customQuery' => Item::active(), # Custom query builder
])
📖 AI_USAGE_GUIDE.md - Non-technical guide
📖 AI_TECHNICAL_REFERENCE.md - Technical deep dive
You define columns (simple list)
['key' => 'title', 'label' => 'Title']
['key' => 'category_name', 'relation' => 'category:name']
['key' => 'subitems_count', 'label' => 'Sub-items']
System auto-detects
withCount()Single optimized query executes
SELECT * FROM items
WITH category
WITH COUNT subitems
WHERE title LIKE ?
ORDER BY created_at ASC
LIMIT 50
Results display instantly ⚡
User clicks "Sort by Price"
↓
Livewire triggers update
↓
Component rebuilds query with ORDER BY
↓
Query executes (1 query only!)
↓
Blade template updates
↓
User sees sorted table
@livewire('aftable', [
'model' => 'App\Models\Item',
'columns' => [
['key' => 'title', 'label' => 'Item Name'],
['key' => 'code', 'label' => 'Code'],
['key' => 'category_name', 'label' => 'Category', 'relation' => 'category:name'],
['key' => 'amount', 'label' => 'Amount', 'value_type' => 'price'],
['key' => 'items_count', 'label' => 'Related Items'],
['key' => 'quantity', 'label' => 'Quantity'],
],
])
@livewire('aftable', [
'model' => 'App\Models\User',
'records' => 25,
'columns' => [
['key' => 'name', 'label' => 'Name'],
['key' => 'email', 'label' => 'Email'],
['key' => 'department_name', 'label' => 'Department', 'relation' => 'department:name'],
['key' => 'is_active', 'label' => 'Status', 'value_type' => 'boolean'],
['key' => 'created_at', 'label' => 'Joined', 'value_type' => 'date'],
],
])
@livewire('aftable', [
'model' => 'App\Models\Order',
'columns' => [
['key' => 'id', 'label' => 'Order #'],
['key' => 'customer_name', 'label' => 'Customer', 'relation' => 'customer:name'],
['key' => 'total_amount', 'label' => 'Total', 'value_type' => 'price'],
['key' => 'items_count', 'label' => 'Items'],
['key' => 'status', 'label' => 'Status'],
['key' => 'created_at', 'label' => 'Date', 'value_type' => 'date'],
],
])
@livewire('aftable', [
'tableClass' => 'w-full border-collapse',
'theadClass' => 'bg-gray-100',
'rowClass' => 'hover:bg-gray-50',
])
@livewire('aftable', [
'model' => 'App\Models\Item',
'customQuery' => Item::active()->whereTenantId(auth()->user()->tenant_id),
])
@livewire('aftable', [
'showExport' => true,
'exportFormats' => ['csv', 'excel', 'pdf'],
])
Enable printable: true to show a Print button that opens an isolated pop-up window containing only the table — no surrounding layout.
@livewire('aftable', [
'model' => App\Models\User::class,
'columns' => [...],
'printable' => true,
'printConfig' => [
'title' => 'User Report',
'header' => '<p>Confidential — Internal Use Only</p>',
'footer' => 'HR Department',
'fontSize' => 11, // pt (default 11)
'orientation' => 'landscape', // portrait | landscape
'paperSize' => 'A4',
'showDate' => true,
'showPageNum' => true,
'tableClass' => 'table-striped',
],
])
Note: Requires the browser to allow pop-ups for your domain.
All three are equivalent — pick the one that fits your workflow:
{{-- 1. Blade helper (most common) --}}
@livewire('aftable', ['model' => App\Models\User::class, 'columns' => [...]])
{{-- 2. Livewire tag syntax --}}
<livewire:aftable :model="App\Models\User::class" :columns="$columns" />
{{-- 3. @aftable directive with optional custom table markup --}}
@aftable(['model' => App\Models\User::class, 'columns' => [...]])
<table class="table table-hover my-custom-theme">
<thead class="bg-dark text-white"><tr></tr></thead>
<tbody></tbody>
</table>
@endaftable
The live code generator at index.html supports all three via the Output Syntax radio group.
<!-- In resources/views/products/index.blade.php -->
@livewire('aftable', [
'model' => 'App\Models\Product',
'columns' => [...],
])
// DON'T do this:
class MyComponent extends Component {
public function render() {
// Don't use @livewire here
}
}
Rule: Component must be used directly in Blade views, NOT instantiated in PHP!
Solution: Run composer require artflow-studio/table
Solution: Use 'relation' => 'relationName:columnName' format for related data
Solution: Only database fields are sortable. Use actual column names.
Solution: Search only works on text columns. Numbers, dates won't search.
Solution: Verify relation exists on model and column name is correct
| File | Purpose | Audience |
|---|---|---|
| README.md | This file - Overview | Everyone |
| USAGE_STUB.md | Complete method reference | Developers, AI agents |
| AI_USAGE_GUIDE.md | How to use (non-technical) | Users, AI agents |
| AI_TECHNICAL_REFERENCE.md | How it works (technical) | Developers, AI agents |
| FEATURE_RECOMMENDATIONS.md | Future features & roadmap | Architects, Planners |
| CHANGELOG_V1.8.0.md | v1.8.0 release notes (Blaze, #[Computed], @island) | Developers |
| CHANGELOG_V1.6.0.md | v1.6.0 & v1.7.0 release notes | Developers |
This package is open-source and available under the MIT license.
ArtFlow Table 1.8.0 - Where Performance Meets Simplicity ⚡
Make datatables simple and fast with automatic optimization!
Last Updated: July 2025
Status: ✅ Production Ready