dytechltd/custom-table
Laravel package for building customizable data tables with dynamic columns, filtering, sorting, pagination, and row actions. Configure tables quickly from your models or arrays without repetitive Blade markup.
Treat dytechltd/custom-table as a small Nova dashboard card, not a full table/CRUD package. It is best for “latest X” panels: recent orders, signups, posts, tickets, etc.
Before installing, inspect the repository in this order:
README.md for the exact card class, registration snippet, and publish tags.composer.json for the laravel/nova version constraint and PHP version. A 2020 release is likely Nova 2/3 era, not Nova 4/5.src/ for the card class and service provider.resources/js/ for the Vue component and props contract.dist/js/ to see whether compiled assets are committed. If not, you will need to build them.Minimal setup, assuming the package exposes a standard Nova card:
composer require dytechltd/custom-table
php artisan vendor:publish --provider="Dytechltd\CustomTable\CustomTableServiceProvider"
php artisan nova:publish
php artisan optimize:clear
Register the card in app/Providers/NovaServiceProvider.php:
use Dytechltd\CustomTable\CustomTable;
public function cards(Request $request)
{
return [
(new CustomTable)->width('full'),
];
}
If the namespace/class differs, follow the README. Then verify the card appears on /nova and inspect the browser console/network response if it is blank.
First practical use case: a “Latest orders” card showing the 5 most recent orders with order number, customer, status, and total, linking to the Nova order detail page. Keep the query bounded:
Order::query()
->latest()
->limit(5)
->get(['id', 'number', 'customer_name', 'status', 'total'])
->map(fn ($order) => [
'id' => $order->id,
'number' => $order->number,
'customer' => $order->customer_name,
'status' => $order->status,
'total' => $order->total,
'url' => Nova::path()."/resources/orders/{$order->id}",
])
->all();
Pass that data to the Vue component through the card’s withMeta() or whatever data method the package exposes. If it has no data method, subclass the card and call withMeta() in the constructor or override jsonSerialize().
Use the package as a thin dashboard presentation layer. Keep queries in PHP card classes, pass small arrays to Vue, and let the card render a simple table. Avoid passing Eloquent models directly to the frontend.
A typical implementation pattern:
use Laravel\Nova\Card;
class LatestOrdersCard extends Card
{
public $component = 'custom-table';
public function __construct()
{
$this->withMeta([
'title' => 'Latest orders',
'columns' => [
['key' => 'number', 'label' => 'Order'],
['key' => 'customer', 'label' => 'Customer'],
['key' => 'status', 'label' => 'Status'],
['key' => 'total', 'label' => 'Total'],
],
'rows' => $this->rows(),
]);
}
private function rows(): array
{
return \App\Models\Order::query()
->latest()
->limit(5)
->get(['id', 'number', 'customer_name', 'status', 'total'])
->map(fn ($order) => [
'number' => $order->number,
'customer' => $order->customer_name,
'status' => $order->status,
'total' => $order->total,
'url' => \Laravel\Nova\Nova::path()."/resources/orders/{$order->id}",
])
->all();
}
}
Common day-to-day patterns:
NovaServiceProvider::cards() for the main dashboard, or in a custom Nova dashboard’s cards() method. Use width('1/2'), width('full'), etc. if the card inherits Nova’s width helpers.LatestOrdersCard, LatestUsersCard, OpenTicketsCard. Do not overgeneralize one card with dozens of conditionals.cards(Request $request) and scope queries with $request->user(). Do not rely on the card to enforce authorization.Gate::allows() before exposing rows. A dashboard card can easily bypass the normal Nova resource authorization flow.Cache::remember() if the data does not need to be real-time.Nova::path() or the resource’s uriKey() rather than hardcoding /nova/resources/....columns/rows shape. Keep the Vue side dumb and the PHP side responsible for formatting.package.json and the Nova constraint before investing./nova-api/cards response, and whether the Vue component name in the card class matches the registered component. Run php artisan nova:publish, clear caches, and rebuild assets if needed.Model::all() or load relationships indiscriminately. Use latest()->limit(5) and explicit select().vendor:publish fails, inspect publishes() in the provider rather than guessing the tag.withMeta() for data, subclass the card for query logic, and fork/publish the Vue component for layout changes. If the package hardcodes columns in Vue, passing new columns metadata may not be enough.How can I help you explore Laravel packages today?