asignua/filament-group-summaries
A Filament plugin that adds grouped summary rows to tables, letting you aggregate columns by group—such as sums, counts, or averages—directly in resource listings. Configure summaries quickly without writing custom table logic.
Install the package with Composer and, if you plan to restyle the summary strip, publish its views/config:
composer require <vendor>/<package>
php artisan vendor:publish --tag="<package>-views"
First use case: attach summarizers to your table/resource so a footer row shows column totals and a group header shows a per-group figure. The mental model is small — a summarizer is an object that produces markup via toHtml() — so the fastest way to learn the API is to render one summarizer in isolation and dump the output:
dump($summarizer->toHtml());
That single call tells you most of what you need: whether the values are being flattened, whether your custom view is being resolved, and what markup the stylesheet is expected to target.
Where to look first:
Values and friends) to see how toHtml() composes output.hideTrailingSummary() below).Footer summaries for totals, header summaries for context. The common shape is a footer summarizer per numeric column (sum/average/count, typically built from Values) and a header summarizer for the group-level figure. Since both header and footer now render through toHtml(), the two are symmetric: anything you can do in a footer, you can do in a header.
Custom rendering with ->view(). Both header and footer summarizers accept a custom view. Reach for this as soon as the default markup doesn't match your design system:
ColumnSummary::make('amount')
->summarizer(Values::make()->view('tables.summaries.amount'))
Keep the custom view deliberately small — pass the summarizer's computed data in, render plain markup out. Because the header path flattens block-level tags (see Gotchas), write header views as inline content wrapped in spans; save richer, block-structured markup for footers.
Published view overrides over per-instance views. If you want a consistent look across every table, override the package view once after publishing rather than passing ->view() everywhere. Per-instance ->view() is best reserved for one-off columns; global view overrides are the lower-maintenance option and automatically pick up the toHtml() path in both header and footer.
Values for multi-part output. Values is the go-to when a single summary needs several pieces (e.g. a total plus a unit, or a count plus a percentage). With v1.0.1, a Values block that has a custom view is no longer flattened in the header strip, so a custom view now renders intact in both positions — meaning you can adopt one view for both header and footer rather than maintaining a separate "header-safe" variant.
Keep custom views dependency-free. Summarizer views are rendered in a strip context, potentially many times per page (per column, per group). Avoid N+1 queries inside them; compute the data in the summarizer and pass it down.
Testing. Assert on toHtml() output rather than on a full rendered page. This keeps tests fast and isolates the summarizer from panel/layout concerns:
$this->assertStringContainsString('1,250.00', $summarizer->toHtml());
hideTrailingSummary() needs the stylesheet. This is the single most common source of "it works but looks broken" reports. Inside a panel, register the package CSS as a panel asset so it loads with the rest of the panel's styles; outside a panel (standalone Livewire page, custom layout, mail/PDF context) you must link the stylesheet by hand. If the trailing summary is visible when it shouldn't be, the CSS almost certainly isn't loaded — check the rendered <head> before you go debugging the PHP.
Header markup is flattened. Block-level tags that implicitly close a <p> — <pre>, <blockquote>, <figure>, <nav>, and the surrounding family (<div>, <section>, <ul>, <table>, headings, etc.) — are flattened to <span> inside the header strip, and <hr> is dropped entirely. Practical consequences: don't expect line breaks, indentation, or horizontal rules to survive in a header summary. Style spans with CSS instead, or move the rich content to the footer.
Upgrading from 1.0.0 changes header output. Two behaviour changes to watch on upgrade: header summarizers now render through toHtml() (so a custom ->view() starts taking effect in headers where it previously didn't), and Values with a custom view is no longer flattened. Both are improvements, but they will change rendered markup — re-check any HTML assertions or snapshot tests that cover group headers.
Custom view not appearing? Resolution order is per-instance ->view() → published override → package default. Clear the view cache after publishing overrides (php artisan view:clear), and double-check the published file kept the package's original filename/path so it's actually picked up.
Don't rely on <p> nesting in summaries. Given the implicit-close rules, a <p> in a header view will be closed early by the next block tag. Prefer spans end-to-end in anything that may render in a header.
Extension points. Beyond ->view() and published views, subclassing the summarizer and overriding toHtml() gives you full control over the output envelope. Use it sparingly — custom views cover most needs and are easier to upgrade across releases.
Debugging shortcut. When markup looks wrong, dump toHtml() directly and compare against the raw view output. That immediately tells you whether the problem is in your view, in the summarizer's value computation, or in the header flattening pass.
How can I help you explore Laravel packages today?