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

Quick Links Laravel Package

niladam/quick-links

Quick Links is a Laravel package for defining and rendering configurable shortcut links in your app. Register links, customize labels and URLs, and output them via Blade components—handy for dashboards, menus, and admin panels.

View on GitHub
Deep Wiki
Context7

Getting Started

niladam/quick-links adds small action links (create/edit/export/etc.) to the header area of a Filament table — the strip where the heading, description and header actions live. v2 is the first release that supports Filament v4 and v5 as well as v3, so it is the version to install on any new panel.

composer require niladam/quick-links

Requirements to check before installing: PHP 8.2+ (up from 8.1 in v1) and filament/tables ^3.0|^4.0|^5.0, which is now a declared dependency rather than an implicit one. On a large app, run composer why-not filament/tables first — a constraint conflict here will surface at install time now, where in v1 the package could be installed next to a mismatched tables version and break at render time.

The first use case is a resource table that needs a "Create" link plus one or two outbound links (CSV export, external docs, an admin tool). Attach it where you build the table:

use Niladam\QuickLinks\QuickLinks;

public static function table(Table $table): Table
{
    return $table
        ->heading('Users')
        ->description('Everyone with access to the panel')
        ->header(
            QuickLinks::make()
                ->resourceLinks([
                    'create' => UserResource::getUrl('create'),
                ])
                ->fileLinks([
                    'export' => route('users.export'),
                ])
        )
        // ... columns, filters
}

Where to look first:

  1. UPGRADING.md — if you are coming from v1, read this before touching code; four public methods changed their return types and disableIf() changed meaning (see Gotchas).
  2. The published Blade view — v2 renders through a view rather than string concatenation, so the markup is inspectable and overridable. Publish it with php artisan vendor:publish --tag=quick-links-views.
  3. Your table's header state — links render via the tables::header.after hook, which only exists when the header container is visible. Confirm your target table has a heading, description, header actions, search, filters or a column manager (see the known limitation below).

Implementation Patterns

Separate "resource" links from "file" links. buildResourceLinks() and buildFileLinks() are the two builders, and in v2 both return arrays of ['url' => ..., 'label' => ...] rather than HTML. Keeping the two kinds distinct means you can, for example, suppress resource links for read-only roles while leaving a static documentation link visible.

Conditional visibility, evaluated per render. disableIf() now runs its closure on each render rather than once at registration, and a closure returning true disables the links. That makes request-dependent checks safe and correct:

QuickLinks::make()
    ->resourceLinks(['create' => UserResource::getUrl('create')])
    ->disableIf(fn () => ! auth()->user()?->can('create', User::class))

This is the idiomatic way to gate the whole set. For gating individual links, filter the input array before passing it in — the builder takes a plain array, so array_filter with a policy check is clearer than nesting conditions.

Panel-wide defaults via a base resource. Because the component is just a table header object, the cleanest integration is a BaseResource (or a HasQuickLinks trait) that returns a configured QuickLinks instance, letting individual resources override the array:

protected static function quickLinks(): QuickLinks
{
    return QuickLinks::make()
        ->resourceLinks([
            'create' => static::getUrl('create'),
            'trash'  => static::getUrl('index', ['trashed' => true]),
        ]);
}

Then ->header(static::quickLinks()) in each resource's table().

Custom markup via the published view. If you need different markup — a dropdown instead of inline anchors, icons, a divider — publish the view and edit it once. The view receives structured links (arrays), not pre-rendered anchors, so you control the markup entirely without touching PHP. This is the intended extension point in v2 and is far more robust than the v1 approach of string-patching returned HTML.

Bypass the component and render the links yourself. Because buildResourceLinks() and buildFileLinks() return plain arrays, you can consume them anywhere — a custom Blade partial in headerActions, a JSON response for a SPA, or an email digest of admin shortcuts. This is also the escape hatch for the header-hidden limitation: call the builders and place the links in a headerActions action or a custom view.

build() as an Htmlable. build() now returns a View (typed ?Htmlable). If you have a method that previously typed ?HtmlString, change the return type to ?Htmlable; the value remains echoable, so {{ $links }} in Blade keeps working.

Testing. With the Pest suite in mind, assert against rendered output rather than internals — assertSee('Create'), assertSee(UserResource::getUrl('create')) — and add one test per role for the disableIf() closure. If you support several Filament majors, mirror the package's own CI matrix: PHP 8.2/8.3/8.4 against Filament v3, v4 and v5, since header-hook behaviour is the one place where the majors can diverge.

Gotchas and Tips

Links silently disappear on bare tables. The render hook lives inside the table header container, which Filament hides when the table has no heading, description, header actions, search, filters or column manager. A table with only columns and rows will render the component but show nothing. Fix: give the table a ->heading(...), or move the links into headerActions. This is the most likely "it worked in v1" complaint, because v1 wrote into description() and always had a container.

description() is no longer overwritten. v1 replaced the table description with the links; v2 appends after the header and leaves your description intact. If you were relying on the links replacing the description, your table now shows both — adjust the layout rather than re-adding the old behaviour.

disableIf() semantics changed in two ways. It now evaluates per render instead of once at registration, and a closure returning true disables the links — v1 inverted the result and disabled the package globally. Audit every disableIf() call after upgrading; a closure that was written around the old inversion will now do the opposite of what you intended. The upside is that auth(), request() and route parameters are all available and current inside the closure.

Don't string-concatenate the builders any more. buildResourceLinks() and buildFileLinks() return arrays. Any code doing '<div>'.$links.'</div>' or str_replace on the output will break loudly — which is preferable to silent breakage, but it means the upgrade touches view code, not just composer.json.

filament/tables is now a real dependency. Previously it was imported but never required, so a project could install the package against an incompatible tables version. Adding the constraint is correct but may block composer update on apps pinned to an old Filament. This is an install-time blocker, not a runtime one — resolve constraints deliberately rather than with --ignore-platform-reqs.

PHP 8.2 floor. Shared CI images, Dockerfiles and older Laravel deployments still on 8.1 will fail to install. Bump the platform requirement across the whole pipeline in the same change, or the package update will be reverted for the wrong reason.

Debugging a missing render. In order: (1) does the table have a header container at all; (2) is disableIf() returning true — temporarily replace the closure with fn () => false; (3) is a stale compiled view shadowing the published one — php artisan view:clear; (4) is the published view in resources/views/vendor/quick-links actually the one being used (check view:cache in production deploys).

Extension points, in order of preference. Publish and edit the Blade view; consume the array builders to render elsewhere; wrap the component in your own class that pre-configures the arrays. Avoid subclassing and overriding the build methods — they changed signatures in v2 and are the most likely thing to move again.

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.
novasa/laravel-language-center
opencage/geocode
adolfoholzer/parameters
livenetworks/ln-starter
shitoudev/permissionmanager
johannesclimacus/laravel-tui
hocvt/seotools
vitalybaev/sypexgeo
amphibee/themosis-ignition
gito-me/fast-excel
frankyso/laravel-ipaymu
geolize-studio/laravel-chile
boomerangui/chat
cgv/localized-resource
noith/settings
kda/laravel-package
kda/filament-dynamic-navigation
bypersoft/signbox
pairus/product-data
fayne/laravel-filament-cms-core