or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

app-lifecycle.mdconfiguration.mdcore.mddata-fetching.mdhead.mdindex.mdmodule-dev.mdnavigation.mdperformance.mdssr.mdstate.md

navigation.mddocs/

0

# Navigation & Routing

1

2

Vue Router integration with programmatic navigation, route middleware, and layout management. Nuxt provides enhanced routing capabilities with file-based routing, nested layouts, and powerful navigation utilities.

3

4

> **Note**: This module uses Vue Router types. In a real application, these are available through Nuxt's auto-imports or can be imported from 'vue-router'.

5

6

## Capabilities

7

8

### Router Access

9

10

Access Vue Router instance and current route information.

11

12

```typescript { .api }

13

/**

14

* Get the Vue Router instance

15

* @returns Vue Router instance

16

*/

17

function useRouter(): Router;

18

19

/**

20

* Get the current route information

21

* @returns Current route object with params, query, meta, etc.

22

*/

23

function useRoute(): RouteLocationNormalizedLoaded;

24

25

interface Router {

26

/** Navigate to a route */

27

push(to: RouteLocationRaw): Promise<NavigationFailure | void | undefined>;

28

/** Replace current route */

29

replace(to: RouteLocationRaw): Promise<NavigationFailure | void | undefined>;

30

/** Go back in history */

31

back(): void;

32

/** Go forward in history */

33

forward(): void;

34

/** Go to specific history position */

35

go(delta: number): void;

36

/** Add route dynamically */

37

addRoute(route: RouteRecordRaw): () => void;

38

/** Remove route by name */

39

removeRoute(name: string | symbol): void;

40

/** Check if route exists */

41

hasRoute(name: string | symbol): boolean;

42

/** Get all routes */

43

getRoutes(): RouteRecord[];

44

/** Resolve route location */

45

resolve(to: RouteLocationRaw): RouteLocation & { href: string };

46

/** Current route */

47

currentRoute: Readonly<Ref<RouteLocationNormalizedLoaded>>;

48

/** Navigation guards */

49

beforeEach(guard: NavigationGuardWithThis<undefined>): () => void;

50

beforeResolve(guard: NavigationGuardWithThis<undefined>): () => void;

51

afterEach(guard: NavigationHookAfter): () => void;

52

}

53

54

interface RouteLocationNormalizedLoaded {

55

/** Route name */

56

name?: string | symbol;

57

/** Route path */

58

path: string;

59

/** Route parameters */

60

params: RouteParams;

61

/** Query parameters */

62

query: LocationQuery;

63

/** Hash fragment */

64

hash: string;

65

/** Route meta information */

66

meta: RouteMeta;

67

/** Full URL including domain */

68

fullPath: string;

69

/** Matched route records */

70

matched: RouteRecordNormalized[];

71

/** Redirected from route */

72

redirectedFrom?: RouteLocation;

73

}

74

```

75

76

**Usage Examples:**

77

78

```typescript

79

// Get router and route

80

const router = useRouter();

81

const route = useRoute();

82

83

// Access route information

84

console.log("Current path:", route.path);

85

console.log("Route params:", route.params);

86

console.log("Query params:", route.query);

87

console.log("Route name:", route.name);

88

89

// Router navigation

90

await router.push("/users");

91

await router.push({ name: "users-id", params: { id: "123" } });

92

await router.replace("/home");

93

94

// History navigation

95

router.back();

96

router.forward();

97

router.go(-2);

98

99

// Dynamic routes

100

router.addRoute({

101

name: "admin",

102

path: "/admin/:section",

103

component: AdminComponent,

104

meta: { requiresAuth: true }

105

});

106

107

// Watch route changes

108

watch(route, (to, from) => {

109

console.log(`Navigated from ${from.path} to ${to.path}`);

110

});

111

112

// Reactive route parameters

113

const userId = computed(() => route.params.id);

114

watch(userId, (newId) => {

115

if (newId) {

116

fetchUser(newId);

117

}

118

});

119

```

120

121

### Programmatic Navigation

122

123

Navigate programmatically with enhanced features and error handling.

124

125

```typescript { .api }

126

/**

127

* Navigate to a route programmatically

128

* @param to - Route location to navigate to

129

* @param options - Navigation options

130

* @returns Navigation result or redirect response

131

*/

132

function navigateTo(

133

to: RouteLocationRaw,

134

options?: NavigateToOptions

135

): Promise<void | NavigationFailure | false> | false | void;

136

137

/**

138

* Abort the current navigation

139

* @param err - Optional error information

140

*/

141

function abortNavigation(err?: string | Partial<NuxtError>): void;

142

143

interface NavigateToOptions {

144

/** Replace current route instead of pushing */

145

replace?: boolean;

146

/** HTTP redirect code for SSR */

147

redirectCode?: number;

148

/** Navigate to external URL */

149

external?: boolean;

150

/** Open in new window/tab */

151

open?: {

152

target: string;

153

windowFeatures?: Record<string, any>;

154

};

155

}

156

```

157

158

**Usage Examples:**

159

160

```typescript

161

// Basic navigation

162

await navigateTo("/users");

163

164

// With parameters

165

await navigateTo(`/users/${userId}`);

166

await navigateTo({ name: "users-id", params: { id: userId } });

167

168

// With query parameters

169

await navigateTo({

170

path: "/search",

171

query: { q: "nuxt", category: "framework" }

172

});

173

174

// Replace current route

175

await navigateTo("/home", { replace: true });

176

177

// External navigation

178

await navigateTo("https://nuxt.com", { external: true });

179

180

// Open in new tab

181

await navigateTo("/docs", {

182

open: {

183

target: "_blank",

184

windowFeatures: {

185

width: 1200,

186

height: 800

187

}

188

}

189

});

190

191

// Server-side redirects

192

await navigateTo("/login", { redirectCode: 302 });

193

194

// Conditional navigation

195

if (!user.value) {

196

await navigateTo("/login");

197

}

198

199

// Navigation with error handling

200

try {

201

await navigateTo("/protected-route");

202

} catch (error) {

203

console.error("Navigation failed:", error);

204

await navigateTo("/error");

205

}

206

207

// Abort navigation

208

function onBeforeLeave() {

209

if (hasUnsavedChanges.value) {

210

abortNavigation("You have unsaved changes");

211

}

212

}

213

```

214

215

### Route Middleware

216

217

Add and manage route middleware for authentication, authorization, and other route-level logic.

218

219

```typescript { .api }

220

/**

221

* Add route middleware dynamically

222

* @param name - Middleware name or function

223

* @param middleware - Middleware function if name is string

224

* @param options - Middleware options

225

*/

226

function addRouteMiddleware(

227

name: string | RouteMiddleware,

228

middleware?: RouteMiddleware,

229

options?: AddRouteMiddlewareOptions

230

): void;

231

232

/**

233

* Define route middleware with proper typing

234

* @param middleware - Middleware function

235

* @returns The middleware function

236

*/

237

function defineNuxtRouteMiddleware(middleware: RouteMiddleware): RouteMiddleware;

238

239

type RouteMiddleware = (

240

to: RouteLocationNormalized,

241

from: RouteLocationNormalized

242

) => NavigationGuardReturn | Promise<NavigationGuardReturn>;

243

244

interface AddRouteMiddlewareOptions {

245

/** Whether middleware is global */

246

global?: boolean;

247

}

248

249

type NavigationGuardReturn =

250

| void

251

| Error

252

| RouteLocationRaw

253

| boolean

254

| NavigationGuardNextCallback;

255

```

256

257

**Usage Examples:**

258

259

```typescript

260

// Define middleware inline

261

addRouteMiddleware((to) => {

262

if (to.path === "/admin" && !user.value?.isAdmin) {

263

return navigateTo("/login");

264

}

265

});

266

267

// Define named middleware

268

addRouteMiddleware("auth", (to) => {

269

if (!user.value) {

270

return navigateTo("/login");

271

}

272

});

273

274

// Global middleware

275

addRouteMiddleware("track-analytics", (to) => {

276

analytics.page(to.path);

277

}, { global: true });

278

279

// Middleware in separate file (middleware/auth.ts)

280

export default defineNuxtRouteMiddleware((to) => {

281

const { user } = useAuth();

282

283

if (!user.value) {

284

throw createError({

285

statusCode: 401,

286

statusMessage: "Authentication required"

287

});

288

}

289

});

290

291

// Complex middleware with async operations

292

defineNuxtRouteMiddleware(async (to) => {

293

const { user, refresh } = useAuth();

294

295

// Refresh user data if needed

296

if (!user.value) {

297

await refresh();

298

}

299

300

// Check permissions

301

const hasPermission = await checkUserPermission(to.meta.permission);

302

if (!hasPermission) {

303

throw createError({

304

statusCode: 403,

305

statusMessage: "Insufficient permissions"

306

});

307

}

308

});

309

310

// Middleware with redirect

311

defineNuxtRouteMiddleware((to) => {

312

const { user } = useAuth();

313

314

if (to.path.startsWith("/admin") && user.value?.role !== "admin") {

315

return navigateTo("/dashboard");

316

}

317

318

if (to.path === "/profile" && !user.value?.emailVerified) {

319

return navigateTo("/verify-email");

320

}

321

});

322

```

323

324

### Navigation Guards

325

326

Set up navigation guards for component-level route handling.

327

328

```typescript { .api }

329

/**

330

* Add route leave guard

331

* @param guard - Navigation guard function

332

*/

333

function onBeforeRouteLeave(guard: NavigationGuard): void;

334

335

/**

336

* Add route update guard

337

* @param guard - Navigation guard function

338

*/

339

function onBeforeRouteUpdate(guard: NavigationGuard): void;

340

341

type NavigationGuard = (

342

to: RouteLocationNormalized,

343

from: RouteLocationNormalized,

344

next: NavigationGuardNext

345

) => NavigationGuardReturn | Promise<NavigationGuardReturn>;

346

```

347

348

**Usage Examples:**

349

350

```typescript

351

// Prevent leaving with unsaved changes

352

onBeforeRouteLeave((to, from, next) => {

353

if (hasUnsavedChanges.value) {

354

const answer = confirm("You have unsaved changes. Do you really want to leave?");

355

if (answer) {

356

next();

357

} else {

358

next(false);

359

}

360

} else {

361

next();

362

}

363

});

364

365

// Handle route parameter changes

366

onBeforeRouteUpdate(async (to, from) => {

367

if (to.params.id !== from.params.id) {

368

await fetchUser(to.params.id);

369

}

370

});

371

372

// Save scroll position

373

onBeforeRouteLeave(() => {

374

const scrollPosition = window.scrollY;

375

sessionStorage.setItem(`scroll-${route.path}`, scrollPosition.toString());

376

});

377

```

378

379

### Layout Management

380

381

Manage page layouts dynamically.

382

383

```typescript { .api }

384

/**

385

* Set the layout for the current page

386

* @param layout - Layout name to use

387

*/

388

function setPageLayout(layout: string): void;

389

```

390

391

**Usage Examples:**

392

393

```typescript

394

// Set layout based on user role

395

const { user } = useAuth();

396

watch(user, (newUser) => {

397

if (newUser?.role === "admin") {

398

setPageLayout("admin");

399

} else {

400

setPageLayout("default");

401

}

402

});

403

404

// Conditional layout

405

if (route.path.startsWith("/dashboard")) {

406

setPageLayout("dashboard");

407

}

408

409

// Mobile vs desktop layout

410

const isMobile = useMediaQuery("(max-width: 768px)");

411

watch(isMobile, (mobile) => {

412

setPageLayout(mobile ? "mobile" : "desktop");

413

});

414

```

415

416

### Advanced Navigation Patterns

417

418

```typescript

419

// Breadcrumb navigation

420

const breadcrumbs = computed(() => {

421

const matched = route.matched.filter(record => record.meta?.breadcrumb);

422

return matched.map(record => ({

423

name: record.meta.breadcrumb,

424

path: record.path,

425

params: route.params

426

}));

427

});

428

429

// Tab navigation with query sync

430

const activeTab = computed({

431

get: () => route.query.tab || "overview",

432

set: (tab) => {

433

router.push({

434

query: { ...route.query, tab }

435

});

436

}

437

});

438

439

// Search with history

440

const searchQuery = ref("");

441

const searchHistory = useState<string[]>("search-history", () => []);

442

443

const performSearch = async (query: string) => {

444

// Add to history

445

if (query && !searchHistory.value.includes(query)) {

446

searchHistory.value.unshift(query);

447

searchHistory.value = searchHistory.value.slice(0, 10); // Keep last 10

448

}

449

450

// Navigate with query

451

await navigateTo({

452

path: "/search",

453

query: { q: query }

454

});

455

};

456

457

// Route-based modal

458

const showModal = computed(() => route.query.modal === "true");

459

460

const openModal = () => {

461

router.push({

462

query: { ...route.query, modal: "true" }

463

});

464

};

465

466

const closeModal = () => {

467

const { modal, ...query } = route.query;

468

router.push({ query });

469

};

470

471

// Multi-step form navigation

472

const currentStep = computed(() =>

473

parseInt(route.params.step as string) || 1

474

);

475

476

const nextStep = () => {

477

const next = currentStep.value + 1;

478

router.push({

479

name: "form-step",

480

params: { step: next.toString() }

481

});

482

};

483

484

const previousStep = () => {

485

if (currentStep.value > 1) {

486

const prev = currentStep.value - 1;

487

router.push({

488

name: "form-step",

489

params: { step: prev.toString() }

490

});

491

}

492

};

493

```

494

495

## Types

496

497

```typescript { .api }

498

type RouteLocationRaw = string | RouteLocationPathRaw | RouteLocationNamedRaw;

499

500

interface RouteLocationPathRaw {

501

path: string;

502

query?: LocationQueryRaw;

503

hash?: string;

504

}

505

506

interface RouteLocationNamedRaw {

507

name: string | symbol;

508

params?: RouteParamsRaw;

509

query?: LocationQueryRaw;

510

hash?: string;

511

}

512

513

type RouteParams = Record<string, string | string[]>;

514

type RouteParamsRaw = Record<string, string | string[] | number | number[]>;

515

type LocationQuery = Record<string, string | string[]>;

516

type LocationQueryRaw = Record<string, string | string[] | number | number[] | null | undefined>;

517

518

interface RouteMeta {

519

[key: string | number | symbol]: unknown;

520

}

521

522

interface RouteRecordRaw {

523

path: string;

524

name?: string | symbol;

525

component?: Component;

526

components?: Record<string, Component>;

527

redirect?: RouteLocationRaw | ((to: RouteLocationNormalized) => RouteLocationRaw);

528

alias?: string | string[];

529

children?: RouteRecordRaw[];

530

meta?: RouteMeta;

531

props?: boolean | Record<string, any> | ((to: RouteLocationNormalized) => Record<string, any>);

532

beforeEnter?: NavigationGuardWithThis<undefined> | NavigationGuardWithThis<undefined>[];

533

sensitive?: boolean;

534

strict?: boolean;

535

}

536

537

interface NavigationFailure extends Error {

538

type: NavigationFailureType;

539

from: RouteLocationNormalized;

540

to: RouteLocationNormalized;

541

}

542

543

enum NavigationFailureType {

544

aborted = 4,

545

cancelled = 8,

546

duplicated = 16

547

}

548

549

type NavigationGuardNext = (to?: RouteLocationRaw | false | ((vm: ComponentPublicInstance) => any) | void) => void;

550

551

type NavigationGuardNextCallback = (vm: ComponentPublicInstance) => any;

552

553

type NavigationGuardWithThis<T> = (

554

this: T,

555

to: RouteLocationNormalized,

556

from: RouteLocationNormalized,

557

next: NavigationGuardNext

558

) => NavigationGuardReturn | Promise<NavigationGuardReturn>;

559

560

type NavigationHookAfter = (

561

to: RouteLocationNormalized,

562

from: RouteLocationNormalized,

563

failure?: NavigationFailure | void

564

) => any;

565

```

566

567

### Accessibility Features

568

569

Accessibility utilities for route announcements and screen reader support.

570

571

```typescript { .api }

572

/**

573

* Set up route announcements for screen readers

574

* @param opts - Configuration options for route announcer

575

* @returns Route announcer utilities

576

*/

577

function useRouteAnnouncer(opts?: RouteAnnouncerOptions): RouteAnnouncer;

578

579

interface RouteAnnouncerOptions {

580

/** ARIA politeness level for announcements */

581

politeness?: 'polite' | 'assertive';

582

/** Skip announcement for these routes */

583

skipRoutes?: string[];

584

/** Custom message formatter */

585

formatMessage?: (route: RouteLocationNormalized) => string;

586

}

587

588

interface RouteAnnouncer {

589

/** Announce current route */

590

announce(): void;

591

/** Skip next announcement */

592

skip(): void;

593

/** Set custom announcement message */

594

set(message: string): void;

595

}

596

```

597

598

**Usage Example:**

599

600

```typescript

601

<script setup>

602

import { useRouteAnnouncer } from "nuxt/app";

603

604

const announcer = useRouteAnnouncer({

605

politeness: 'polite',

606

skipRoutes: ['/api'],

607

formatMessage: (route) => `Navigated to ${route.meta.title || route.path}`

608

});

609

610

// Manually announce

611

announcer.announce();

612

613

// Skip next automatic announcement

614

announcer.skip();

615

616

// Custom announcement

617

announcer.set('Welcome to the dashboard');

618

</script>

619

```

620

621

## Additional Types

622

623

```typescript { .api }

624

interface RouteAnnouncerOptions {

625

/** ARIA politeness level for announcements */

626

politeness?: 'polite' | 'assertive';

627

/** Skip announcement for these routes */

628

skipRoutes?: string[];

629

/** Custom message formatter */

630

formatMessage?: (route: RouteLocationNormalized) => string;

631

}

632

633

interface RouteAnnouncer {

634

/** Announce current route */

635

announce(): void;

636

/** Skip next announcement */

637

skip(): void;

638

/** Set custom announcement message */

639

set(message: string): void;

640

}

641

```