> ## Documentation Index
> Fetch the complete documentation index at: https://mintlify.com/tighten/ziggy/llms.txt
> Use this file to discover all available pages before exploring further.

# Vue

> Using Ziggy with Vue 2 and Vue 3 applications

## Installation

Ziggy includes a Vue plugin that makes the `route()` helper available throughout your Vue application—in templates, component scripts, and the Options API.

### Basic Setup with @routes

If you're using the `@routes` Blade directive, Ziggy's config is available globally. Simply install the plugin:

```js theme={null}
import { createApp } from 'vue';
import { ZiggyVue } from 'ziggy-js';
import App from './App.vue';

createApp(App)
    .use(ZiggyVue)
    .mount('#app');
```

### Setup Without @routes

If you're not using `@routes`, import and pass Ziggy's configuration to the plugin:

```js theme={null}
import { createApp } from 'vue';
import { ZiggyVue } from 'ziggy-js';
import { Ziggy } from './ziggy.js'; // Generated by php artisan ziggy:generate
import App from './App.vue';

createApp(App)
    .use(ZiggyVue, Ziggy)
    .mount('#app');
```

## Usage in Templates

Once the plugin is installed, use `route()` directly in your templates:

```vue theme={null}
<template>
    <nav>
        <a :href="route('home')" class="nav-link">Home</a>
        <a :href="route('posts.index')" class="nav-link">Blog</a>
        <a :href="route('posts.show', { post: post.id })" class="nav-link">
            {{ post.title }}
        </a>
    </nav>
</template>

<script>
export default {
    props: ['post'],
};
</script>
```

## Vue 3 Composition API

The ZiggyVue plugin provides the `route()` function via Vue's dependency injection system.

### Using `inject()` with `<script setup>`

In Vue 3's `<script setup>`, use `inject()` to access the `route()` function:

```vue theme={null}
<template>
    <div>
        <h1>{{ post.title }}</h1>
        <a :href="route('posts.index')" class="back-link">
            ← Back to all posts
        </a>
    </div>
</template>

<script setup>
import { inject } from 'vue';
import { ref } from 'vue';

const route = inject('route');
const props = defineProps(['postId']);

// Use route() in your script
const fetchPost = async () => {
    const response = await fetch(route('api.posts.show', { post: props.postId }));
    return response.json();
};
</script>
```

### Standard Composition API

```vue theme={null}
<template>
    <a :href="postUrl" class="post-link">View Post</a>
</template>

<script>
import { inject, computed } from 'vue';

export default {
    props: ['post'],
    setup(props) {
        const route = inject('route');
        
        const postUrl = computed(() => {
            return route('posts.show', { post: props.post.id });
        });
        
        return { postUrl };
    },
};
</script>
```

## Vue 2 Support

ZiggyVue automatically detects Vue 2 and registers `route()` as a global method:

```vue theme={null}
<template>
    <div>
        <a :href="route('posts.index')">All Posts</a>
    </div>
</template>

<script>
export default {
    mounted() {
        // Access route() via this in Vue 2
        console.log(this.route('posts.index'));
    },
};
</script>
```

## Complete Examples

### Navigation Component

```vue theme={null}
<template>
    <header class="site-header">
        <nav>
            <router-link 
                v-for="item in navigation" 
                :key="item.name"
                :to="item.path"
            >
                {{ item.label }}
            </router-link>
        </nav>
    </header>
</template>

<script setup>
import { inject, computed } from 'vue';

const route = inject('route');

const navigation = computed(() => [
    { name: 'home', label: 'Home', path: route('home') },
    { name: 'about', label: 'About', path: route('about') },
    { name: 'contact', label: 'Contact', path: route('contact') },
]);
</script>
```

### Form Submission

```vue theme={null}
<template>
    <form @submit.prevent="handleSubmit">
        <input v-model="post.title" type="text" required />
        <textarea v-model="post.body" required></textarea>
        <button type="submit">{{ isEditing ? 'Update' : 'Create' }}</button>
    </form>
</template>

<script setup>
import { inject, ref, computed } from 'vue';
import axios from 'axios';

const route = inject('route');
const props = defineProps({
    post: Object,
});

const isEditing = computed(() => !!props.post?.id);

const handleSubmit = async () => {
    const url = isEditing.value
        ? route('posts.update', { post: props.post.id })
        : route('posts.store');
    
    const method = isEditing.value ? 'put' : 'post';
    
    await axios[method](url, props.post);
};
</script>
```

### Data Fetching with Composables

```vue theme={null}
<template>
    <div>
        <div v-if="loading">Loading...</div>
        <div v-else-if="error">Error: {{ error }}</div>
        <div v-else>
            <h1>{{ post.title }}</h1>
            <p>{{ post.body }}</p>
        </div>
    </div>
</template>

<script setup>
import { inject, ref, onMounted } from 'vue';

const route = inject('route');
const props = defineProps(['postId']);

const post = ref(null);
const loading = ref(true);
const error = ref(null);

const fetchPost = async () => {
    try {
        loading.value = true;
        const response = await fetch(route('api.posts.show', { post: props.postId }));
        post.value = await response.json();
    } catch (e) {
        error.value = e.message;
    } finally {
        loading.value = false;
    }
};

onMounted(fetchPost);
</script>
```

## TypeScript Support

To use Ziggy with TypeScript in Vue, you need to declare the `route` property on Vue's component interface.

### Vue 3 TypeScript Declaration

Create a `ziggy.d.ts` file in your project:

```ts theme={null}
// ziggy.d.ts
import { route as routeFn } from 'ziggy-js';

declare module 'vue' {
    interface ComponentCustomProperties {
        route: typeof routeFn;
    }
}

export {};
```

This enables TypeScript to recognize `route()` in your templates and Options API components without type errors.

### Using with `<script setup lang="ts">`

```vue theme={null}
<template>
    <a :href="route('posts.show', { post: props.post })" class="post-link">
        {{ post.title }}
    </a>
</template>

<script setup lang="ts">
import { inject } from 'vue';
import { route as routeFn } from 'ziggy-js';

interface Post {
    id: number;
    title: string;
    slug: string;
}

const route = inject<typeof routeFn>('route')!;
const props = defineProps<{
    post: Post;
}>();
</script>
```

### Typed Route Parameters

For full type safety with route names and parameters, generate Ziggy's type definitions:

```bash theme={null}
php artisan ziggy:generate --types
```

Then your routes will have full autocomplete:

```vue theme={null}
<script setup lang="ts">
import { inject } from 'vue';
import type { route as routeFn } from 'ziggy-js';

const route = inject<typeof routeFn>('route')!;

// TypeScript knows 'posts.show' exists and requires a 'post' parameter
const url = route('posts.show', { post: 1 });
</script>
```

## Plugin Implementation

The ZiggyVue plugin is implemented as follows:

```js theme={null}
export const ZiggyVue = {
    install(app, options) {
        const r = (name, params, absolute, config = options) =>
            route(name, params, absolute, config);

        if (parseInt(app.version) > 2) {
            // Vue 3: Add to global properties and provide for inject()
            app.config.globalProperties.route = r;
            app.provide('route', r);
        } else {
            // Vue 2: Add as a mixin method
            app.mixin({
                methods: {
                    route: r,
                },
            });
        }
    },
};
```

The plugin automatically passes the config you provide to `.use(ZiggyVue, config)` to every `route()` call, so you don't need to pass it manually.

## Troubleshooting

### `route is not defined` in templates

Ensure you've installed the ZiggyVue plugin:

```js theme={null}
import { ZiggyVue } from 'ziggy-js';
app.use(ZiggyVue);
```

### `inject()` returns undefined

Make sure the plugin is installed before mounting your app, and that you're using Vue 3.

### TypeScript errors in templates

Add the module declaration for `ComponentCustomProperties` as shown in the TypeScript section above.

## Next Steps

<CardGroup cols={2}>
  <Card title="TypeScript" icon="code" href="/typescript">
    Set up full type safety and autocompletion
  </Card>

  <Card title="React" icon="react" href="/react">
    Use Ziggy with React instead
  </Card>

  <Card title="Route Helper" icon="route" href="/route-function">
    Learn all route() function capabilities
  </Card>

  <Card title="JavaScript Frameworks" icon="js" href="/javascript-frameworks">
    General framework integration guide
  </Card>
</CardGroup>
