tightenco/ziggy
Ziggy brings Laravel’s named routes to JavaScript with a route() helper that mirrors Laravel’s. Generate URLs client-side with parameters, model binding, and TypeScript support, and filter which routes are exposed. Works with Vue, React, SPAs, and separate repos.
composer require tightenco/ziggy
@routes in your main layout file (e.g., resources/views/layouts/app.blade.php) before your JavaScript bundles:
@routes
@vite(['resources/js/app.js'])
route() function in JavaScript like Laravel’s PHP helper:
// Generate URL for a named route
const url = route('posts.index'); // e.g., "/posts"
Route Generation:
route('route.name') → /uri.route('posts.show', 1); // "/posts/1"
route('posts.show', { post: 1 }); // Same as above
route('posts.index', { page: 2 }); // "/posts?page=2"
route('posts.show', { post: 1, _query: { sort: 'new' } }); // "/posts/1?sort=new"
Framework Integration:
ZiggyVue plugin for global route() access:
import { createApp } from 'vue';
import { ZiggyVue } from 'ziggy-js';
createApp(App).use(ZiggyVue);
Access in templates:
<a :href="route('home')">Home</a>
useRoute() hook:
const route = useRoute();
<a href={route('dashboard')}>Dashboard</a>
SPA/Static Sites:
php artisan ziggy:generate
import { route } from 'ziggy-js';
import { Ziggy } from './ziggy.js';
route('home', {}, {}, Ziggy);
TypeScript Support:
php artisan ziggy:generate --types
route for autocompletion:
declare global { var route: typeof import('ziggy-js').route; }
Route Filtering:
@routes includes all routes in HTML. Omit sensitive routes:
Ziggy::routes(function () {
return ['posts.*', 'auth.*']; // Only include these
});
Ziggy::ignore() to exclude routes:
Ziggy::ignore(['admin.*']);
Parameter Mismatches:
if (!route().has('posts.show')) console.error('Route missing!');
Model Binding Quirks:
getRouteKeyName() must match Laravel’s binding. Ziggy uses id by default:
// Fails if Post uses `slug` but JS passes `id`
route('posts.show', { id: 1 }); // "/posts/1" (not slug)
SPA Caching:
ziggy.js after route changes:
php artisan ziggy:generate --force
Inspect Routes:
console.log(route().routes);
console.log(route().params); // { venue: "1", event: "2" }
TypeScript Strict Mode:
declare module 'ziggy-js' {
interface TypeConfig { strictRouteNames: true; }
}
Query Parameter Conflicts:
_query to avoid overriding route params:
route('posts.show', { post: 1, _query: { post: 'draft' } });
// "/posts/1?post=draft" (not "/posts/draft")
Vue/React Edge Cases:
ZiggyVue/useRoute is initialized before components mount.@routes from server-side rendering (use client-side only).Custom Route Metadata:
Ziggy::with(['auth' => auth()->check()]);
Access in JS:
if (Ziggy.auth) { /* ... */ }
Dynamic Route Prefixes:
Ziggy.url in JS for multi-tenant apps:
route('home', {}, {}, { ...Ziggy, url: 'https://tenant1.app' });
Webpack/Vite Aliases:
// vite.config.js
resolve: { alias: { 'ziggy-js': '/vendor/tightenco/ziggy' } }
How can I help you explore Laravel packages today?