LiveVue 1.0
Examples Navigation

Navigation

LiveView-aware navigation with the Link component and useLiveNavigation() hook. Choose between full page loads, LiveView navigation, or patching with query params.

What this example shows

1
Link Component
href, navigate, patch
2
useLiveNavigation()
Programmatic navigation
3
Query Params
Patching with replace
Navigation.vue
<script setup lang="ts">
import { computed } from 'vue'
import { Link, useLiveNavigation } from 'live_vue'

const props = defineProps<{
  currentPath: string
  queryParams: Record<string, string>
}>()

const { navigate, patch } = useLiveNavigation()

const sections = ['overview', 'details', 'settings']
const selectedSection = computed(() => props.queryParams.section || 'overview')

function selectSection(section: string) {
  patch({ section }, { replace: true })
}

function goToCounter() {
  navigate('/examples/counter')
}
</script>

<template>
  <div class="card bg-base-200 p-6 space-y-6">
    <div class="space-y-3">
      <div class="text-sm font-medium text-neutral">Current Location</div>
      <div class="p-4 rounded-lg bg-base-300 font-mono text-sm">
        <div class="text-neutral text-xs mb-1">Path:</div>
        <div class="text-primary mb-3">{{ props.currentPath }}</div>
        <div class="text-neutral text-xs mb-1">Query Params:</div>
        <div class="whitespace-pre">{{
          Object.keys(props.queryParams).length > 0
            ? JSON.stringify(props.queryParams, null, 2)
            : '{}'
        }}</div>
      </div>
    </div>

    <div class="border-t border-base-300 pt-6 space-y-3">
      <div class="text-sm font-medium text-neutral">
        Link Component (declarative)
      </div>
      <div class="flex flex-col gap-3">
        <div class="flex items-center gap-3">
          <Link :patch="`${props.currentPath}?filter=active`" class="btn btn-ghost btn-sm">
            patch
          </Link>
          <span class="text-xs text-neutral">Updates URL params, keeps LiveView state</span>
        </div>
        <div class="flex items-center gap-3">
          <Link :patch="`${props.currentPath}?filter=active&id=123`" replace class="btn btn-ghost btn-sm">
            patch + replace
          </Link>
          <span class="text-xs text-neutral">Same as patch, but replaces browser history</span>
        </div>
        <div class="flex items-center gap-3">
          <Link navigate="/examples/events" class="btn btn-ghost btn-sm">
            navigate
          </Link>
          <span class="text-xs text-neutral">Navigates to Events example (new LiveView)</span>
        </div>
        <div class="flex items-center gap-3">
          <Link href="https://vuejs.org" class="btn btn-ghost btn-sm">
            href
          </Link>
          <span class="text-xs text-neutral">Full page load to vuejs.org</span>
        </div>
      </div>
    </div>

    <div class="border-t border-base-300 pt-6 space-y-3">
      <div class="text-sm font-medium text-neutral">
        useLiveNavigation() Hook (programmatic)
      </div>
      <div class="flex flex-col gap-3">
        <div class="flex items-center gap-3">
          <button @click="patch({ sort: 'desc', page: '2' })" class="btn btn-secondary btn-sm">
            patch()
          </button>
          <span class="text-xs text-neutral">Adds sort=desc & page=2 to URL</span>
        </div>
        <div class="flex items-center gap-3">
          <button @click="goToCounter" class="btn btn-primary btn-sm">
            navigate()
          </button>
          <span class="text-xs text-neutral">Navigates to Counter example (new LiveView)</span>
        </div>
      </div>
    </div>

    <div class="border-t border-base-300 pt-6 space-y-3">
      <div class="text-sm font-medium text-neutral">
        Section Navigation (patch with replace)
      </div>
      <div class="flex gap-1 p-1 bg-base-300 rounded-lg w-fit">
        <button
          v-for="section in sections"
          :key="section"
          @click="selectSection(section)"
          :class="[
            'py-2 px-4 rounded-md text-sm font-medium transition-all capitalize',
            selectedSection === section
              ? 'bg-base-200 shadow-sm'
              : 'text-neutral hover:text-base-content'
          ]"
        >
          {{ section }}
        </button>
      </div>
      <div class="p-4 rounded-lg bg-base-300">
        <div class="text-sm capitalize">{{ selectedSection }} content goes here</div>
      </div>
    </div>
  </div>
</template>

How it works

1 Link component for declarative navigation

The Link component provides three navigation modes: href for normal links, navigate for LiveView navigation with new state, and patch for updating params while preserving state.

<Link navigate="/users">Users</Link>

2 useLiveNavigation() for programmatic control

When you need to navigate based on logic or user actions, use the useLiveNavigation() composable. It provides navigate() and patch() functions.

const { navigate, patch } = useLiveNavigation()

3 Patch with query params and replace

Use patch() to update query parameters without adding a history entry. Pass an object of params and options like replace: true to avoid cluttering the browser history.

patch({ tab: 'profile' }, { replace: true })

4 handle_params tracks navigation changes

LiveView's handle_params callback fires whenever the URL changes. Use it to update assigns based on the new path and query params, which then flow down as props to your Vue components.

def handle_params(params, uri, socket)
Next up: Simple Form with useLiveForm()
View example →