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

Expandable Row Laravel Package

sprigs/expandable-row

Sprigs Expandable Row is a Laravel/PHP package that adds collapsible expandable rows to tables and list views, letting users reveal extra details inline without navigating away. A small, focused tool for cleaner, more informative admin panels and data-heavy interfaces.

View on GitHub
Deep Wiki
Context7

Getting Started

  1. Install and verify the package name. The repo is SPRIGS/nova-expandable-row, so confirm the actual Packagist name before committing — composer require sprigs/expandable-row and check composer show sprigs/expandable-row resolves. A 4-star, 0-dependent package is a small blast radius but also means the README may be the only documentation.
  2. Read src/ before touching a real Resource. Look for the service provider (asset registration / Nova::script / Nova::style), then the main class that implements the row behaviour. With packages this small, the source is the docs — usually one trait or one field class you attach to a Resource.
  3. Register if needed. Laravel auto-discovery covers most Nova packages, but check composer.json for a extra.laravel.providers block. If absent, add the provider to config/app.php or NovaServiceProvider::register().
  4. Publish assets if the provider calls publishes(). Run php artisan vendor:publish --provider="Sprigs\\ExpandableRow\\..." (grep the provider for the exact namespace) and then php artisan nova:publish.
  5. First use case: pick one internal Resource — orders, tickets, audit logs — where the detail modal is slow or where reviewers scan many rows in sequence. Apply the package there only, keep the stock modal everywhere else, and compare before/after with ?perPage=25.

Implementation Patterns

Opt-in per Resource, not globally. Resist applying it to every Resource at once. A common shape is a base App\Nova\Resource that pulls in the package's trait/behaviour, with individual Resources overriding the "which fields go in the expanded row" method. That keeps the surface area to one class you can revert.

Curate the expanded payload deliberately. The modal renders the full detail view; an expanded row renders inside a <tr>. Restrict the expanded content to scalar fields — Text, DateTime, Badge, Boolean — and leave File, KeyValue, Textarea with long content, and any field with its own heavy sub-request in the modal. If the package exposes a method like expandableFields() or a fields() override on the row class, that is your allowlist.

Eager-load what the row needs. The biggest practical win of killing the modal is avoiding one extra request per row — don't reintroduce it. If the expanded row touches a relation, add it to indexQuery():

public static function indexQuery(NovaRequest $request, $query)
{
    return $query->with(['customer:id,name', 'assignee:id,name']);
}

Watch Telescope/Debugbar on the index page; an N+1 here multiplies by page size.

Compose with the existing table rather than replacing it. Keep searchable/sortable columns in the normal index columns and treat the expanded area as supplementary detail. This preserves filters, sorting and the perPage selector, which a full-view replacement usually breaks.

Wire it into an existing workflow, not a new one. The good use case is a triage screen: filters narrow to 20 rows, the developer/ops user expands 3, reads the detail, clicks an action (Action / inline button) without navigating. Pair it with row actions so expansion replaces "click View → do thing → back".

Treat it as a UI layer over viewAny. Whatever the package does, verify it doesn't call the detail endpoint. Test as a user with a policy that denies view but allows viewAny — the expanded row should either hide fields or not render at all.

Gotchas and Tips

  • Version compatibility is the real risk. Nova 4 vs Nova 5 changed asset/build conventions. With 4 stars and no dependents, assume it was built against one Nova major. Pin it, and smoke-test the index page (not just the detail page) after every Nova upgrade.
  • Abandonment plan required. Nothing else depends on this package, so a fork is cheap. Vendor it under packages/ with a path repository if you intend to keep it long-term — that's usually cheaper than waiting for a PR.
  • State loss on navigation. Expansion is client-side; paginating, sorting, filtering or hitting the search box will collapse rows. Don't build a workflow that assumes an expanded row survives a filter change.
  • Authorization gaps. If the package renders a detail-style preview, it may bypass the view policy or expose fields the modal would have gated. Grep the source for authorize / canSee. Field-level canSee() on individual fields is usually still respected — confirm.
  • Field rendering context. Fields behave differently outside the detail view: Textarea collapses, Stack/Line may need explicit widths, Badge and Status are fine. Test in dark mode and at narrow widths — a <tr> has far less room than a modal.
  • Asset caching bites first. If the UI doesn't change after composer update, run php artisan nova:publish, php artisan view:clear, and hard-reload — Nova's compiled assets are a classic false-negative when debugging.
  • Debugging: network tab first. If expanding a row fires an XHR, that's the cost you were trying to avoid; if it's pure DOM, the payload for the page just got bigger and perPage should come down (25 → 15) for wide Resources.
  • Extension points are limited by design. A package this size rarely ships config publishables. Expect to subclass or bind your own implementation rather than configure. If you need behaviour it doesn't support, extend the class in app/Nova/ rather than patching vendor/.
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.
takashato/laravel-vietqr
aitor24/laralang
kraenzle-ritter/entity-relations
dindigital/din-image
pomirleanu/image-colors
sawmainek/laravel-api-generator
delatbabel/jsonresponses
mouhamedfd/permissions-generator
eduplus/qr
laravel2580/idehelpers
delatbabel/viewpages
anavel/gettext
muhamadrezaar/highcharts
delatbabel/keylists
frankkessler/salesforce-laravel-oauth2-rest
anavel/foundation
wdmtech/enviricons
eii/laravel-captcha
muka/shape-reader
tdt/json