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 List Card Laravel Package

dillingham/nova-list-card

Laravel Nova List Card displays model records in a compact, customizable dashboard list. Configure the model, columns, sort order, and result limit to surface recent or important items at a glance, making it easy to build quick overviews and search-style result lists.

View on GitHub
Deep Wiki
Context7

Getting Started

Install

composer require dillingham/nova-list-card

No manual provider registration is needed on Laravel 5.5+ (package discovery). If you've disabled discovery, register the package's service provider from composer.json → extra.laravel.providers.

Where to look first

  • README.md — short, but it's the canonical list of fluent setters.
  • src/ListCard.php — the entire server-side API is a handful of setters that build an Eloquent query and serialize props to the card. Read this file before reading anything else; it takes about two minutes and removes all guesswork about which methods actually exist in the 2020 release.
  • resources/js/components/Card.vue — what the props actually render (row layout, avatar slot, link behaviour). If a prop isn't read here, passing it from PHP does nothing.

First use case

The card exists to replace a bare metric ("Users: 412") with a "here are the newest 5" list. Drop it into your dashboard's cards() method:

// app/Nova/Dashboards/Main.php
use Dillingham\NovaListCard\ListCard;

public function cards()
{
    return [
        (new ListCard)
            ->model(\App\Models\User::class)
            ->title('Newest users')
            ->icon('user')
            ->sortBy('created_at', 'desc')
            ->limit(5)
            ->url('/resources/users'),
    ];
}

Refresh the dashboard. Each row is one model, titled by the model's Nova title ($title / title() convention) and linked to url with the model key appended. If the card renders but is empty, you're sorting on a column that doesn't exist or the model has no created_at.

Implementation Patterns

Dashboard composition. Treat the card as a dashboard building block, not a one-off. A typical ops dashboard is four to six of these stacked in a width('1/3') grid, one per model, each limited to 5–10 rows:

(new ListCard)->model(Order::class)->title('Latest orders')->icon('shopping-cart')->sortBy('created_at', 'desc')->limit(8)->width('1/3'),
(new ListCard)->model(Invoice::class)->title('Overdue invoices')->icon('cash')->sortBy('due_at', 'asc')->limit(8)->width('1/3'),
(new ListCard)->model(Ticket::class)->title('Open tickets')->icon('exclamation')->sortBy('updated_at', 'desc')->limit(8)->width('1/3'),

Extract a base card for house defaults. Dashboards get noisy fast. Subclass once so every dashboard entry stays a one-liner:

namespace App\Nova\Cards;

use Dillingham\NovaListCard\ListCard;

class RecentOrders extends ListCard
{
    public function __construct()
    {
        parent::__construct();

        $this->model(\App\Models\Order::class)
            ->title('Recent orders')
            ->icon('shopping-cart')
            ->sortBy('created_at', 'desc')
            ->limit(10)
            ->url('/resources/orders');
    }
}

Then (new RecentOrders)->width('1/2') in the dashboard. This is also the cleanest place to hang a custom query if model() + sortBy() isn't enough — see below.

Scoping beyond a plain sort. The card builds a straightforward Model::query()->orderBy(...)->limit(...). For "only unread", "only my team's", or "only this tenant", you have two clean options without forking the vendor code:

  1. Point the card at a dedicated read model / global scope (e.g. a PublishedPost model with a global scope), or
  2. Subclass ListCard and override the query-building method you'll find in src/ListCard.php (usually resolveCards/cards-style helper) to apply ->where(...) before the limit.

The second is the intended extension point; the package is small enough that this is a five-line override.

Row linking. url() takes the resource base path; the model key is appended per row. Use Nova's path helper rather than hardcoding if you mount Nova at a custom path:

->url(Nova::path().'/resources/users')

Avatars. The card supports rendering an avatar in the row (the feature exists for user-style lists). Verify the exact setter name in src/ListCard.php against your installed version — the README examples are authoritative — and make sure the underlying column (email for Gravatar, or an avatar/image attribute) is present on the model, or rows render with the placeholder.

Gate the card, not the query. For role-specific dashboards, use Nova's standard card visibility rather than branching inside cards():

(new ListCard)
    ->model(Invoice::class)
    ->canSee(fn () => request()->user()->hasRole('finance'))

Same for placement: ->onlyOnDashboard(), ->onlyOnDetail(), ->exceptOnDashboard() all come from Nova's base Card.

Performance shape. One card = one HTTP call to /nova-api/cards on dashboard load. Each card is also one SELECT ... ORDER BY ... LIMIT n. Add a database index on whatever column you pass to sortBy() (especially created_at on large tables) and keep limit() honest — 5 to 10 rows, not 50.

Gotchas and Tips

It's a Nova 3-era package (last release mid-2020). That's the single biggest risk. Nova 4 moved to Vue 3 and changed card bootstrapping, so the pre-compiled dist/js/card.js shipped here will likely fail to register on Nova 4/5 — you get a card with no component, or a console error like "Failed to mount component". Before committing: install it, load a dashboard, and check the browser console. If it's broken, your options are (a) fork, bump the laravel-nova dev dependency, adjust resources/js/card.js to the new Nova.booting((app, store) => ...) signature, and rebuild, or (b) hand-roll a tiny custom card. Budget for that.

A failed card can take the whole dashboard's card request down. The card's props are serialized server-side during the /nova-api/cards call. A bad ->model(SomeClassThatDoesNotExist::class), a missing column in sortBy(), or a model whose table doesn't exist throws a 500 on that endpoint — and in Nova's dashboard that often surfaces as every card disappearing, not just this one. When a dashboard goes blank, comment out cards one at a time, or check storage/logs/laravel.log and the network tab for the cards response.

Sorting on a column that isn't there fails silently-ish. ->sortBy('due_at', 'asc') on a model without due_at produces a SQL error (see above). Directions are lowercase 'asc'/'desc'; anything else in older Laravel query builders defaults unpredictably.

Blank row titles. Rows display the model's Nova title. A model with no $title property and no title() method (and no name attribute Nova can fall back to) shows an empty or ID-only row. Define public function title(): string on the model or pass the attribute the card should display, per the README.

The card bypasses your Nova policies. ->model(User::class) queries the table directly at dashboard-render time; it does not run UserPolicy::viewAny. A user who can reach the dashboard sees those rows, and the row links will 403 when clicked. For anything sensitive, wrap with ->canSee(...), or scope the query in a subclass so the card is only ever fed records the viewer may see.

Empty lists render an empty card body — no friendly "nothing here yet" state in the bundled Vue component. Two portable workarounds: gate with canSee(fn () => Order::exists()), or edit Card.vue to add an empty-state branch and rebuild (which you may be doing anyway for Nova 4).

withMeta() won't magically show up. It's inherited from Nova's base Card, but the bundled component only reads the props it knows about. If you want to surface extra data (a computed total, a colour, a "view all" link), change resources/js/components/Card.vue and rebuild with npm run dev inside the package, then republish assets.

Asset/build hygiene. If rows render but styling is off, or the card is invisible after a deploy, confirm dist/js/card.js was committed/copied (case-sensitive filesystems bite here) and run php artisan nova:publish / php artisan view:clear after changing anything in the package's dist. If you rebuild the package's JS, the laravel-nova dev dependency must match your Nova major version or the build produces components Nova can't mount.

Debugging order of operations. (1) Does the card appear in the /nova-api/cards JSON payload with the right component and props? If no → PHP-side problem (model, column, provider). (2) Does it appear in the DOM but blank/erroring? If yes → JS-side problem (stale dist, Vue version). That split saves most of the debugging time on this package.

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.
socialdept/atp-orm
cboxdk/laravel-assistant-client
socialdept/atp-resolver
socialdept/tenant-domains
tautvydasr/blade-class-names
socialdept/color-scales
maherelgamil/controller
coleus/widgets
coleus/table
coleus/users
coleus/music
coleus/health
coleus/calendar
coleus/notes
coleus/support
coleus/settings
coleus/apps
seampact/laravel
emmyconceptng/laravel-ng-postcode
jjsquady/round-robin