Stop Click Hijacking: Mastering wire:navigate with Alpine Dialogs

You build a card-style CTA. It’s clickable. It should navigate when tapped.

Inside that card, you also add a tiny button to open a dialog.

Here’s the thing: because the whole card is wrapped in a navigation click, that little button doesn’t stand a chance. Users try to open the dialog… and boom. they’re already on the next page.

I didn’t go hunting strangers or asking every developer forum to bless me. I opened the docs and figured it out.

Livewire Navigation Docs

Before: The Unwanted Navigation

Typical structure:

1<a
2 wire:navigate
3 href="/somewhere"
4 x-data="{ dialogOpen: false }"
5>
6 <button x-on:click="dialogOpen = true">
7 <x-lucide-info />
8 </button>
9 
10 <div
11 x-show="dialogOpen"
12 class="dialog-panel"
13 >
14 <p>Content...</p>
15 </div>
16</a>

Everything looks correct… but a button inside a clickable navigation wrapper = accidental page changes.

You click the info button ➜ navigation fires anyway because the click event bubbles up to <a wire:navigate>.

After: Full Control Navigation Only When You Decide

Instead of letting wire:navigate automatically trigger, we call it manually using Livewire.navigate().

1+ @script
2+ <script>
3+ window.redirectToTarget = () => {
4+ Livewire.navigate(@js(route('target.route', ['param' => $param->id])))
5+ }
6+ </script>
7+ @endscript
8 
9- <div
10- x-data="{ dialogOpen: false }"
11+ x-on:click="redirectToTarget"
12- class="clickable-card"
13- >
14- <h3>
15- Action Title
16- <button
17- type="button"
18- x-on:click.stop.prevent="dialogOpen = true"
19- >
20- <x-lucide-info />
21- </button>
22- </h3>
23-
24- <p>Short description text</p>
25-
26- <div x-show="dialogOpen" class="dialog-panel">
27- <h2>Dialog Title</h2>
28- <p>More info goes here.</p>
29- <button type="button" x-on:click="dialogOpen = false">Close</button>
30- </div>
31- </div>

Why This Works

  • The card itself controls navigation using redirectToTarget()
  • The dialog button stops the click from bubbling up (.stop.prevent)
  • You decide when navigation should fire not the browser

No hacks. No overlays. Just letting Alpine handle UI, and Livewire handle navigation independently.

Key Lesson

When combining Alpine interactions inside click-based navigation:

  • Stop clicks meant for UI elements
  • Trigger navigation programmatically
  • Keep control where it belongs

Sometimes the cleanest solution starts with simply reading the docs.