useLink() | Vue Router - Custom Link Behavior Made Easy ๐ โ
Build custom navigation components - Access RouterLink's internal logic without the rendering constraints!
๐ฏ Function Overview โ
The useLink() composable gives you direct access to the internal behavior of RouterLink without being tied to its default rendering. This is perfect for creating custom navigation components with complete control over the UI while maintaining all the smart routing capabilities.
๐ Basic Usage โ
function useLink<Name extends string | symbol = string | symbol>(
props: UseLinkOptions<Name>
): UseLinkReturn<Name>๐ง Parameters โ
| Parameter | Type | Description |
|---|---|---|
props | UseLinkOptions<Name> | Configuration options including the target location and navigation behavior |
๐ค Returns โ
- Type:
UseLinkReturn<Name> - Description: An object containing all the reactive link properties and methods
๐ก When to Use This Function โ
๐จ Custom UI Components โ
Create navigation elements that don't look like traditional links:
<template>
<button
@click="navigate"
:class="{ active: isActive }"
:aria-current="isActive ? 'page' : undefined"
>
<slot />
</button>
</template>
<script setup>
import { useLink } from 'vue-router'
const props = defineProps({
to: [String, Object],
replace: Boolean
})
const { navigate, isActive } = useLink(props)
</script>๐ง Advanced Navigation Logic โ
Implement complex navigation behavior beyond standard links:
const { navigate, href, route, isActive, isExactActive } = useLink({
to: '/dashboard',
replace: false
})
// Custom navigation with additional logic
function customNavigate() {
if (shouldNavigate()) {
navigate()
trackNavigation()
}
}๐ ๏ธ Practical Examples โ
Example 1: Custom Button Navigation โ
<template>
<button
class="nav-button"
:class="{
'nav-button--active': isActive,
'nav-button--exact-active': isExactActive
}"
@click="handleClick"
:disabled="isDisabled"
>
<span class="nav-button__icon">
<slot name="icon" />
</span>
<span class="nav-button__text">
<slot />
</span>
</button>
</template>
<script setup>
import { computed } from 'vue'
import { useLink } from 'vue-router'
const props = defineProps({
to: [String, Object],
replace: Boolean,
disabled: Boolean
})
const { navigate, isActive, isExactActive, href } = useLink(props)
const isDisabled = computed(() => props.disabled || isActive.value)
function handleClick(event) {
if (!isDisabled.value) {
navigate(event)
// Emit custom event
emit('navigate', { to: props.to, href: href.value })
}
}
</script>
<style scoped>
.nav-button {
padding: 12px 16px;
border: none;
background: transparent;
cursor: pointer;
transition: all 0.2s ease;
}
.nav-button--active {
background: #007bff;
color: white;
}
.nav-button--exact-active {
box-shadow: 0 2px 4px rgba(0, 123, 255, 0.3);
}
.nav-button:disabled {
opacity: 0.6;
cursor: not-allowed;
}
</style>Example 2: Breadcrumb Navigation โ
<template>
<nav class="breadcrumb">
<ol>
<li v-for="(crumb, index) in breadcrumbs" :key="index">
<component
:is="crumb.to ? 'a' : 'span'"
:href="crumb.to ? href : undefined"
@click="crumb.to ? navigate(crumb.to) : null"
:class="{ 'breadcrumb__item--active': !crumb.to }"
>
{{ crumb.label }}
</component>
<span v-if="index < breadcrumbs.length - 1" class="breadcrumb__separator">
/
</span>
</li>
</ol>
</nav>
</template>
<script setup>
import { computed } from 'vue'
import { useLink, useRoute } from 'vue-router'
const route = useRoute()
const breadcrumbs = computed(() => {
const paths = route.path.split('/').filter(Boolean)
return paths.map((path, index) => {
const fullPath = '/' + paths.slice(0, index + 1).join('/')
const isLast = index === paths.length - 1
return {
label: path.charAt(0).toUpperCase() + path.slice(1),
to: isLast ? null : fullPath
}
})
})
// Custom navigation function for breadcrumbs
function navigate(to) {
const { navigate: linkNavigate } = useLink({ to })
linkNavigate()
}
</script>๐ Return Value Properties โ
๐ Reactive Properties โ
| Property | Type | Description |
|---|---|---|
navigate | Function | Function to trigger navigation |
isActive | boolean | Whether the link is active |
isExactActive | boolean | Whether the link is exactly active |
href | string | Resolved URL href |
route | RouteLocationNormalizedLoaded | The target route object |
๐ฏ Best Practices โ
โ Do Use When โ
- Building custom navigation components
- Creating non-link navigation elements (buttons, cards, etc.)
- Implementing complex navigation logic
- Need fine-grained control over navigation behavior
โ Avoid When โ
- Simple link navigation (use
<RouterLink>instead) - Basic navigation without custom UI requirements
- Performance-critical simple navigation
๐ง Advanced Usage Patterns โ
Pattern 1: Programmatic Navigation Control โ
const { navigate, isActive } = useLink({
to: '/target',
replace: false
})
// Control navigation with additional conditions
function controlledNavigate() {
if (userHasPermission()) {
navigate()
} else {
showPermissionError()
}
}Pattern 2: Multi-step Navigation โ
const navigation = useLink({ to: '/wizard/step2' })
async function handleWizardNavigation() {
// Validate current step
if (await validateCurrentStep()) {
navigation.navigate()
} else {
showValidationErrors()
}
}Pattern 3: Analytics Integration โ
const { navigate, href } = useLink({ to: '/target' })
function trackAndNavigate(event) {
// Send analytics before navigation
analytics.track('link_click', {
href: href.value,
timestamp: Date.now()
})
navigate(event)
}๐ Related Components & Functions โ
RouterLink- The standard link componentuseRouter()- Access router instance for programmatic navigationuseRoute()- Access current route information
๐ Performance Considerations โ
โก Lazy Evaluation โ
// Only create link when needed
const link = computed(() =>
isNavigationNeeded.value ? useLink(props) : null
)๐ Memoization โ
import { memoize } from 'lodash-es'
const createLink = memoize((to) => useLink({ to }))
// Reuse link instances for same destinations
const homeLink = createLink('/home')
const aboutLink = createLink('/about')๐ก Pro Tip
Combine useLink() with Vue's defineProps and TypeScript for type-safe custom navigation components that are both powerful and maintainable!
Ready to build custom navigation experiences? Start using
useLink()for complete control over your app's navigation behavior! ๐