The Vue generator includes a <Link> component that enables type-safe navigation with Vue Router - while keeping the simplicity and familiarity of anchor-based links. Rather than writing string paths manually, you provide a tuple that defines both the route template and the parameters needed to fill it.
This ensures that navigating between pages remains reliable and fully checked by TypeScript.
π Tuple-Based Navigation β
Every route generated by KosmoJS includes a typed mapping from tuple values to route parameters. For example:
<Link :to="['users/[id]', 42]">
Open User Profile
</Link>The first tuple value matches the folder structure in pages/, and the second fills the [id] placeholder. TypeScript verifies that:
- the route exists
- the route requires a parameter
- the parameter has the correct type
No more guessing route strings or mismatched URL segments.
β Query-Only Navigation β
If your <Link> specifies only a query object:
<Link :query="{ filter: 'active' }">
Active items
</Link>Then clicking the link stays on the current page while updating search parameters - a great fit for local filtering and sortable tables.
π§± Link.vue Implementation β
The component wraps a simple <a> element and relies on Vue Router under the hood. It constructs the final URL and triggers navigation through router.push() when clicked.
<script setup lang="ts" generic="T extends LinkProps">
import { computed } from "vue";
import { RouterLink, useRoute } from "vue-router";
import { stringify, unwrap } from "@src/{fetch}/lib";
import pageMap from "@src/{pages}";
import type { LinkProps } from "@src/{vue}";
import { baseurl } from "@src/config";
interface Props {
to?: T
query?: Record<string | number, unknown>
replace?: boolean
activeClass?: string
exactActiveClass?: string
}
const props = defineProps<Props>()
const route = useRoute()
const href = computed(() => {
if (props.to) {
const [key, ...params] = props.to
return pageMap[key]?.base(params as never, props.query)
}
const path = route.path.replace(
new RegExp(`^${baseurl.replace(/\/+$/, "")}/`),
"/",
)
return props.query ? [path, stringify(unwrap(props.query))].join("?") : path
})
</script>
<template>
<RouterLink
:to="href"
:replace="replace"
:active-class="activeClass"
:exact-active-class="exactActiveClass"
>
<slot />
</RouterLink>
</template>This approach provides:
- correct URLs even when parameters change
- autocomplete for route templates
- compile-time safety against missing params
- consistent navigation across all source folders
π§© Navigation Helpers β
All navigation logic is centralized inside generated helpers in: