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

Livewire Urls Laravel Package

ralphjsmit/livewire-urls

ralphjsmit/livewire-urls lets you use Laravel's route() helper inside Livewire components, generating URLs from named routes and parameters directly in your component classes. URLs can stay in sync with reactive properties and update automatically as state changes, with no hardcoded paths or Blade w...

View on GitHub
Deep Wiki
Context7

Getting Started

1. Install and pin.

composer require ralphjsmit/livewire-urls
composer show ralphjsmit/livewire-urls   # record the exact resolved version

The package is MIT, 81 stars, zero dependents, and effectively single-maintainer. Pin the exact version in composer.json ("1.7.0", not "^1.7") and commit the lockfile. That is a two-second decision that converts "the maintainer stopped" from an incident into a one-line revert.

2. Read the source before the README. The public surface is small — an attribute class plus the hydration/dehydration hook that maps properties to query keys. Ten minutes in vendor/ralphjsmit/livewire-urls/src will tell you more than the docs, and it settles the ambiguity described in the Gotchas section below. Confirm the attribute's FQCN there; the examples here use #[Url] generically.

3. Check what Livewire already gives you. Livewire 3 ships a native #[Url] attribute. Before adopting, open a scratch component, add the native attribute, and see whether it covers your case. If it does, you do not need this dependency at all — and the honest answer to "should we adopt?" may be "no, but the pattern is right."

4. First use case — a searchable, shareable index page. This is the canonical fit and the one to build first:

use Livewire\Component;
use Livewire\WithPagination;

class UsersIndex extends Component
{
    use WithPagination;

    #[Url]
    public string $search = '';

    #[Url(as: 'status')]
    public string $status = 'all';

    public function render()
    {
        return view('livewire.users-index', [
            'users' => User::query()
                ->when($this->search, fn ($q) => $q->where('name', 'like', "%{$this->search}%"))
                ->when($this->status !== 'all', fn ($q) => $q->where('status', $this->status))
                ->paginate(25),
        ]);
    }
}

Visit /users?search=jane&status=active&page=2 and the component mounts already filtered and already on page 2. Typing in the search box rewrites the query string as you go. That is the whole day-one win: support can now ask "send me the URL" instead of "send me a screenshot and tell me which filters you clicked."

Implementation Patterns

Filter bars with dependent resets. The single most common bug in URL-synced filters is landing on page 7 of a two-page result set. Reset paging whenever a filter changes:

public function updatedSearch(): void  { $this->resetPage(); }
public function updatedStatus(): void  { $this->resetPage(); }

resetPage() from WithPagination writes page=1 back into the URL, so the shared link is always coherent.

Alias every query key you intend to keep. #[Url(as: 'q')], #[Url(as: 'sort')]. The alias is a public contract — someone has it in a bookmark, an email, a support ticket. The property name is not. Aliasing costs one argument up front and saves a breaking-change conversation later when someone wants to rename $search to $searchTerm.

Tabs and wizard steps. The second-best fit after filters:

#[Url(as: 'tab')]
public string $tab = 'general';

Now the settings page has five linkable tabs, onboarding emails can deep-link step 3, and bug reports identify which tab rendered the broken widget. If you have a multi-step flow, also decide whether the step is user-addressable (should be in the URL) or sequence-enforced (probably should not be — otherwise people bookmark step 4 and skip validation).

Keep the URL for state that is worth sharing. A useful test for every candidate property: would I paste this URL into Slack? Search, filters, sort order, active tab, page, date range, selected record — yes. Open modal, expanded rows, hover state, unsaved draft text — no. Every property you mark #[Url] expands your public URL surface and your future compatibility obligations; be deliberate rather than marking everything.

Canonicalize on mount. Query strings are user input. They arrive from bookmarks, crawlers, and people editing the address bar by hand. Validate before it reaches the query builder:

public function mount(): void
{
    $this->status = in_array($this->status, ['all', 'active', 'archived'], true)
        ? $this->status
        : 'all';

    $this->search = substr($this->search, 0, 100);
}

Note that the attribute hydrates before mount() runs, so mount() is the right place to normalize — but do not re-assign a default unconditionally, or you will silently discard every incoming link.

Wrap it in one place. Create a small base component or trait that owns the imports and any defaults. When (not if) you need to swap to Livewire's native attribute, or fork the package, or drop it entirely, the change lands in one file instead of forty.

Use it alongside route params, not instead of them. Query strings are for ephemeral view state; path segments and route model binding are for identity. /users/42?tab=activity is right. /users?tab=activity&id=42 is not — it makes 42 unshareable-on-its-own, invisible to middleware, and impossible to authorize declaratively.

Gotchas and Tips

The package's stated purpose and its documented usage disagree — resolve this first. The repository tagline reads "Get the previous and current url in Livewire" (a URL-history helper), while the usage documentation describes #[Url] query-string binding of component properties. These are different packages with different risk profiles. Before you write a line of code against it, run a five-minute spike and confirm which behavior actually ships in the version you installed. Everything downstream — estimates, architecture notes, whether this belongs in your routing layer — depends on the answer.

Livewire 3 overlaps heavily. If you are on Livewire 3, the framework's own #[Url] likely covers the sync use case. Watch for two failure modes: (a) importing this package's attribute and wondering why the native one's options are ignored, and (b) having both registered on the same property. Pick one, document the choice in your conventions, and make sure the whole team's muscle memory matches.

Never mark sensitive properties. Query strings end up in browser history, server access logs, Referer headers sent to third parties, screenshot tools, and analytics. Tokens, emails, API keys, internal IDs that leak volume or identity, and anything you would not want indexed — keep those in the session or the server, never in #[Url].

Arrays and enums need verification. Confirm how non-scalar properties serialize into the query string and how they deserialize from a hand-edited URL. ?tags[]=a&tags[]=b looks fine in the address bar and can behave surprisingly in mount(). If you need multi-select filters, spike it end-to-end before designing a UI around it.

Booleans are the classic share-link bug. true vs 1 vs on — make sure the round trip is stable. A link that works when you generate it but loses a checkbox when someone pastes it back is a support ticket you will get twice.

Watch for update loops. Property update → URL write → hydration → updated() hook → property update. It usually settles, but updated() hooks that mutate other URL-bound properties are where it stops settling. If you see a component that thrashes on load, comment out the updated* methods first.

Cold-load testing is its own discipline. Do not validate sharing by clicking around your own session. Copy the URL, open a private window, and load it cold. That is the only test that reproduces what a colleague receiving your link actually experiences — no Livewire state, no session, no cached component.

Debugging recipe. When the URL and the component disagree: dump request()->query() at the top of mount() to see what actually arrived, then dump $this after hydration to see what the properties became. The gap between those two dumps is almost always where the bug is. If the URL is not updating on interaction, check that the property is genuinely public — protected and private properties are invisible to the sync mechanism, and the failure is silent.

Version and framework questions to settle before you depend on it. The 1.7.0 release note is a single line: "Laravel 13 support." Confirm (a) whether the illuminate/* constraint was widened (^12|^13) or swapped (^13) — a swap makes this package a gate on your framework upgrade rather than an independent choice; (b) whether the PHP floor moved; and (c) whether Laravel 13 and your Livewire version are actually in the package's CI matrix, or merely allowed by the constraint. A changelog entry is a claim, not a test result.

Sequencing rule for upgrades. Never bump this package in the same change as a framework upgrade. Framework first, suite green, then the package. Otherwise you cannot attribute a failure, and you will spend an afternoon bisecting something that was never related.

The escape hatch is genuinely cheap. At ~81 stars and zero dependents, this is community OSS with a narrow blast radius, not a platform. The MIT license means forking and vendoring is a realistic contingency rather than a theoretical one — the package is small enough that a senior engineer could re-derive its core in a day or two. Adopt on that basis: useful, reversible, not load-bearing. Keep the rationale and pinned version in your dependency register so the next person to touch it knows it was a deliberate, hedged choice.

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.
elsayed85/laravel-api-exceptions
ouhssini/laravel-demo-mode
daworks/ncloud-outbound-mailer-driver
gp247/cms
ignibyte/aic-gates
nexa-merchant/blog
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