Skip to content

Commit cb768bb

Browse files
committed
docs: extending RouterLink
1 parent 244b5fd commit cb768bb

File tree

3 files changed

+114
-1
lines changed

3 files changed

+114
-1
lines changed

docs/.vitepress/config.js

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,10 @@ const config = {
118118
link: '/guide/advanced/lazy-loading',
119119
text: 'Lazy Loading Routes',
120120
},
121+
{
122+
link: '/guide/advanced/extending-router-link',
123+
text: 'Extending RouterLink',
124+
},
121125
{
122126
link: '/guide/advanced/navigation-failures',
123127
text: 'Navigation Failures',

docs/guide/advanced/composition-api.md

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -76,4 +76,32 @@ export default {
7676
}
7777
```
7878

79-
<!-- TODO: useLink -->
79+
Composition API guards can also be used anywhere, they don't have to be used directly on the route component as in-component guards.
80+
81+
## `useLink`
82+
83+
Vue Router exposes the internal behavior of RouterLink as a Composition API function. It gives access the same properties as the [`v-slot` API](#TODO):
84+
85+
```js
86+
import { RouterLink, useLink } from 'vue-router'
87+
88+
export default {
89+
name: 'AppLink',
90+
91+
props: {
92+
// add @ts-ignore if using TypeScript
93+
...RouterLink.props,
94+
inactiveClass: String,
95+
},
96+
97+
setup(props) {
98+
const { route, href, isActive, isExactActive, navigate } = useLink(props)
99+
100+
const isExternalLink = computed(
101+
() => typeof props.to === 'string' && props.to.startsWith('http')
102+
)
103+
104+
return { isExternalLink, href, navigate, isActive }
105+
},
106+
}
107+
```
Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
# Extending RouterLink
2+
3+
The RouterLink component exposes enough `props` to suffice most basic applications but it doesn't try to cover every possible use case and you will likely find yourself using `v-slot` for some advanced cases. In most medium to large sized applications, it's worth creating one if not multiple custom RouterLink components to reuse them across your application. Some examples are Links in a Navigation Menu, handling external links, adding an `inactive-class`, etc.
4+
5+
Let's extend RouterLink to handle external links as well and adding a custom `inactive-class` in an `AppLink.vue` file:
6+
7+
```vue
8+
<template>
9+
<a v-if="isExternalLink" v-bind="$attrs" :href="to" target="_blank">
10+
<slot />
11+
</a>
12+
<router-link v-else v-bind="$props" v-slot="{ isActive, href, navigate }">
13+
<a
14+
v-bind="$attrs"
15+
:href="href"
16+
@click="navigate"
17+
:class="isActive ? activeClass : inactiveClass"
18+
>
19+
<slot />
20+
</a>
21+
</router-link>
22+
</template>
23+
24+
<script>
25+
import { RouterLink } from 'vue-router'
26+
27+
export default {
28+
name: 'AppLink',
29+
30+
props: {
31+
// add @ts-ignore if using TypeScript
32+
...RouterLink.props,
33+
inactiveClass: String,
34+
},
35+
36+
computed: {
37+
isExternalLink() {
38+
return typeof this.to === 'string' && this.to.startsWith('http')
39+
},
40+
},
41+
}
42+
</script>
43+
```
44+
45+
If you prefer using a render function or create `computed` properties, you can use the `useLink` from the [Composition API](./composition-api.md):
46+
47+
```js
48+
import { RouterLink, useLink } from 'vue-router'
49+
50+
export default {
51+
name: 'AppLink',
52+
53+
props: {
54+
// add @ts-ignore if using TypeScript
55+
...RouterLink.props,
56+
inactiveClass: String,
57+
},
58+
59+
setup(props) {
60+
const useLink
61+
const isExternalLink = computed(() => typeof props.to === 'string' && props.to.startsWith('http'))
62+
63+
return { isExternalLink }
64+
}
65+
}
66+
```
67+
68+
In practice, you might want to use your `AppLink` component for different parts of your application. e.g. using [Tailwind CSS](https://tailwindcss.com), you could create a `NavLink.vue` component with all the classes:
69+
70+
```vue
71+
<template>
72+
<AppLink
73+
v-bind="$attrs"
74+
class="inline-flex items-center px-1 pt-1 border-b-2 border-transparent text-sm font-medium leading-5 text-gray-500 focus:outline-none transition duration-150 ease-in-out hover:text-gray-700 hover:border-gray-300 focus:outline-none focus:text-gray-700 focus:border-gray-300 transition duration-150 ease-in-out"
75+
active-class="border-indigo-500 text-gray-900 focus:border-indigo-700"
76+
inactive-class="text-gray-500 hover:text-gray-700 hover:border-gray-300 focus:text-gray-700 focus:border-gray-300"
77+
>
78+
<slot />
79+
</AppLink>
80+
</template>
81+
```

0 commit comments

Comments
 (0)