Weave 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

Nova Table Card Laravel Package

abordage/nova-table-card

A Laravel Nova card that displays model records as a compact, configurable table on your dashboard. Define the data source and columns to give users at-a-glance tabular summaries without leaving Nova.

View on GitHub
Deep Wiki
Context7

Getting Started

  • Install with the version that matches your Nova major. 1.x targets Nova 5; 0.2.x stays on Nova 4. Composer will tell you immediately if you guessed wrong:
    composer require abordage/nova-table-card:^1.0
    
    If you're still on Nova 4, pin ^0.2 and don't upgrade until the Nova upgrade lands.
  • Look at two files first: the package's src/TableCard.php (the abstract base you extend — it defines the column/row contract, title, and width) and the README's example card. Everything else in the package is rendering glue.
  • Register the card where it will be seen. Cards are inert until added to a dashboard or a resource:
    // app/Providers/NovaServiceProvider.php
    public function dashboards()
    {
        return [
            $this->dashboardUsing('main', [
                new \App\Nova\Cards\LatestOrders,
            ]),
        ];
    }
    
  • First use case — a "latest N" snapshot table. Create app/Nova/Cards/LatestOrders.php, extend TableCard, define the column labels and return the row data (an array or a mapped collection). Then hit /nova/dashboards/main and confirm it renders before adding a second card.
  • Nova 5 upgrade path: a major version bump means you should read the package's composer.json before committing. If the constraint is nova: ^5.0, upgrading the card forces the Nova 5 upgrade; if it's ^4.0|^5.0 the bump is safe to take independently. Run the Nova upgrade first, then the card, so you're only debugging one variable.

Implementation Patterns

  • Static snapshot, not a data grid. The card renders whatever rows you hand it at page load. Treat it as a dashboard summary ("top 10 by revenue", "recently failed jobs"), not as a browsable table. Reach for a Nova resource, Lens, or a custom tool when you need sorting, filtering, or pagination.
  • Build rows in PHP, format in PHP. There's no per-column formatter or Vue slot pipeline to lean on, so anything the user sees should already be a string:
    public function rows(): array
    {
        return Order::query()
            ->with('customer:id,name')
            ->latest()
            ->limit(10)
            ->get(['id', 'customer_id', 'total', 'status', 'created_at'])
            ->map(fn (Order $order) => [
                'id'      => $order->id,
                'customer'=> $order->customer?->name ?? '—',
                'total'   => '$' . number_format($order->total / 100, 2),
                'status'  => Str::headline($order->status),
                'placed'  => $order->created_at->diffForHumans(),
            ])
            ->all();
    }
    
    Mapping to plain arrays (rather than ->toArray() on the model) is what keeps accessors and $appends from firing unnoticed.
  • Scope every query to the viewer. Dashboards are gated by Nova's viewNova gate, which is coarse. If the card shows customer data, filter explicitly:
    Order::query()->where('team_id', $request->user()->team_id)
    
    For cards that shouldn't appear at all for some users, implement canSee() / authorizedToSee() on the card rather than returning empty rows — empty tables invite "is it broken?" tickets.
  • Cache the expensive part, not the card. Cards re-query on every dashboard load, and the dashboard is a page people leave open and refresh. Cache::remember('nova.orders-card', 60, fn () => ...) around the row builder keeps an aggregate query off the hot path.
  • Reuse the same card on a resource detail page. Adding it to a resource's cards() method is the cheapest way to show "related records" (e.g. a customer's last five invoices) without writing a custom field or relationship panel — pass context via the card's constructor or resolve().
  • Test the data method, not the rendering. Because rows are plain PHP, a unit test with factories asserting the mapped array shape catches almost every regression:
    $card = new LatestOrders();
    $this->assertSame(['id', 'customer', 'total', 'status', 'placed'], array_keys($card->rows()[0]));
    

Gotchas and Tips

  • 1.0.0 is a major bump for a one-line changelog. The only stated change is Nova 5 support, but semver majors exist to signal breakage. Diff the tag before upgrading a production app — the realistic candidates are a dropped Nova 4 constraint, a raised PHP/Laravel floor inherited from Nova 5, or a renamed method on TableCard. If you subclassed the card, check your overrides still match the parent signatures.
  • ->toArray() is a trap. Calling it on an Eloquent collection serializes dates as ISO strings, triggers $appends accessors (each potentially a query), and leaks any column you selected with *. Always narrow the select and map explicitly.
  • No refresh, no polling. The table is server-rendered per page load; it will not update after an action, and there's no built-in interval. If staleness matters, put a "last updated" timestamp in the card title and let users reload.
  • Styling can drift from the Nova theme. The card ships its own table markup/classes, and Nova 5's frontend changed. If the card looks out of place (borders, dark mode, spacing), publish the package views/assets and override rather than fighting it from your app's CSS — that override is also what you'll maintain across future Nova upgrades.
  • Empty state is on you. Zero rows renders a header with no body. Return a single placeholder row or hide the card via canSee() when the count is zero.
  • Don't put HTML in cells. The rendering isn't a Blade escape hatch; links and badges belong in Nova's own components. If you find yourself wanting {!! !!}, you want a custom card or a resource index instead.
  • Check asset publishing after the Nova 5 upgrade. If you previously ran vendor:publish for this package, re-publish and clear Nova's compiled assets (php artisan nova:publish, then a hard browser refresh) — stale JS from 0.2.x against Nova 5's frontend is the most likely source of a blank card.
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.
mrnewport/laravel-plaid
mrnewport/laravel-repo
mrnewport/laravel-docsign
mrnewport/laravel-stow
mrnewport/laravel-flow
mrnewport/laravel-priceable
mrnewport/laravel-nestedterms
fredmeng/laravel-apidoc-generator
itstructure/laravel-multilingual-tools
pdustdar/elasticsearch
markupai/php-sdk
rlacerda83/lumem-microservice-shipment
uni-method/symfony-lib
tacticmedia/scim-server-bundle
neika-ai/symfony-bundle
mattleads/agent-publishing-bundle
glavweb/framework-bundle
glavweb/extra-bundle
glavweb/api-bundle
glavweb/admin-bundle