
Frontend Routing
- 401 installs
- 305 repo stars
- Updated March 4, 2026
- aj-geddes/useful-ai-prompts
frontend-routing is an agent skill that sets up client-side or hybrid routing, nested layouts, guards, and deep links for developers scaffolding or extending React, Vue, or similar SPAs.
About
frontend-routing is an agent skill in aj-geddes/useful-ai-prompts for establishing navigation structure in single-page applications. The skill covers client-side or hybrid routing, nested layouts, route guards, and deep link handling when scaffolding or extending React, Vue, or comparable frontend stacks. Developers reach for frontend-routing when a new SPA needs consistent URL structure, protected routes, or layout composition before feature pages multiply. The focus is routing architecture and guard patterns rather than backend API design. Use it during frontend build work when navigation behavior must be planned alongside page components.
- Route configuration and nested layouts
- Protected routes and auth guards
- Lazy loading and code-splitting by route
- Deep linking and URL parameter handling
- 404, redirects, and navigation edge cases
Frontend Routing by the numbers
- 401 all-time installs (skills.sh)
- Ranked #664 of 2,245 Frontend Development skills by installs in the Skillselion catalog
- Data as of Aug 5, 2026 (Skillselion catalog sync)
npx skills add https://github.com/aj-geddes/useful-ai-prompts --skill frontend-routingAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 401 |
|---|---|
| repo stars | ★ 305 |
| Last updated | March 4, 2026 |
| Repository | aj-geddes/useful-ai-prompts ↗ |
How do you set up nested routes and guards in SPAs?
Set up client-side or hybrid routing, nested layouts, guards, and deep links when scaffolding or extending a React, Vue, or similar SPA.
Who is it for?
Frontend developers scaffolding or extending React, Vue, or similar SPAs that need structured routing and protected routes.
Skip if: Developers building server-rendered-only sites without client-side routing or backend API idempotency concerns.
When should I use this skill?
A SPA needs client-side or hybrid routing, nested layouts, route guards, or deep-link support during scaffold or extension work.
What you get
Configured client-side routes, nested layouts, guard rules, and working deep-link navigation.
- SPA route configuration
- Nested layout structure
- Route guard rules
Files
Frontend Routing
Table of Contents
Overview
Implement client-side routing with navigation, lazy loading, protected routes, and state management for multi-page single-page applications.
When to Use
- Multi-page navigation
- URL-based state management
- Protected/guarded routes
- Lazy loading of components
- Query parameter handling
Quick Start
Minimal working example:
// App.tsx
import { BrowserRouter, Routes, Route, Navigate } from 'react-router-dom';
import { Layout } from './components/Layout';
import { Home } from './pages/Home';
import { NotFound } from './pages/NotFound';
import { useAuth } from './hooks/useAuth';
import React from 'react';
// Lazy loaded components
const Dashboard = React.lazy(() => import('./pages/Dashboard'));
const UserProfile = React.lazy(() => import('./pages/UserProfile'));
const Settings = React.lazy(() => import('./pages/Settings'));
// Protected route wrapper
const ProtectedRoute: React.FC<{ children: React.ReactNode }> = ({ children }) => {
const { isAuthenticated } = useAuth();
if (!isAuthenticated) {
return <Navigate to="/login" replace />;
}
return <>{children}</>;
};
export const App: React.FC = () => {
// ... (see reference guides for full implementation)Reference Guides
Detailed implementations in the references/ directory:
| Guide | Contents |
|---|---|
| React Router v6 | React Router v6 |
| Vue Router 4 | Vue Router 4 |
| Angular Routing | Angular Routing |
| Query Parameter Handling | Query Parameter Handling |
| Route Transition Effects | Route Transition Effects |
Best Practices
✅ DO
- Follow established patterns and conventions
- Write clean, maintainable code
- Add appropriate documentation
- Test thoroughly before deploying
❌ DON'T
- Skip testing or validation
- Ignore error handling
- Hard-code configuration values
Angular Routing
Angular Routing
// app-routing.module.ts
import { NgModule } from "@angular/core";
import { RouterModule, Routes } from "@angular/router";
import { DashboardComponent } from "./components/dashboard/dashboard.component";
import { AuthGuard } from "./guards/auth.guard";
import { GuestGuard } from "./guards/guest.guard";
const routes: Routes = [
{ path: "", redirectTo: "/home", pathMatch: "full" },
{
path: "home",
loadComponent: () =>
import("./pages/home/home.component").then((m) => m.HomeComponent),
},
{
path: "login",
loadComponent: () =>
import("./pages/login/login.component").then((m) => m.LoginComponent),
canActivate: [GuestGuard],
},
{
path: "dashboard",
component: DashboardComponent,
canActivate: [AuthGuard],
children: [
{
path: "users",
loadChildren: () =>
import("./features/users/users.module").then((m) => m.UsersModule),
},
],
},
{
path: "users/:id",
loadComponent: () =>
import("./pages/user-detail/user-detail.component").then(
(m) => m.UserDetailComponent,
),
canActivate: [AuthGuard],
},
{ path: "**", redirectTo: "/home" },
];
@NgModule({
imports: [RouterModule.forRoot(routes)],
exports: [RouterModule],
})
export class AppRoutingModule {}
// auth.guard.ts
import { Injectable } from "@angular/core";
import {
CanActivate,
ActivatedRouteSnapshot,
RouterStateSnapshot,
Router,
} from "@angular/router";
import { AuthService } from "../services/auth.service";
@Injectable({ providedIn: "root" })
export class AuthGuard implements CanActivate {
constructor(
private authService: AuthService,
private router: Router,
) {}
canActivate(
route: ActivatedRouteSnapshot,
state: RouterStateSnapshot,
): boolean {
if (this.authService.isAuthenticated()) {
return true;
}
this.router.navigate(["/login"], { queryParams: { returnUrl: state.url } });
return false;
}
}
// Component usage
import { Component, OnInit } from "@angular/core";
import { ActivatedRoute, Router } from "@angular/router";
@Component({
selector: "app-user-detail",
templateUrl: "./user-detail.component.html",
})
export class UserDetailComponent implements OnInit {
userId: string | null = null;
tab: string = "profile";
constructor(
private route: ActivatedRoute,
private router: Router,
) {}
ngOnInit(): void {
this.route.params.subscribe((params) => {
this.userId = params["id"];
});
this.route.queryParams.subscribe((params) => {
this.tab = params["tab"] || "profile";
});
}
goHome(): void {
this.router.navigate(["/"]);
}
navigateToTab(tab: string): void {
this.router.navigate([], {
relativeTo: this.route,
queryParams: { tab },
queryParamsHandling: "merge",
});
}
}Query Parameter Handling
Query Parameter Handling
// React Hook for Query Params
import { useSearchParams } from 'react-router-dom';
const SearchUsers: React.FC = () => {
const [searchParams, setSearchParams] = useSearchParams();
const handleSearch = (query: string) => {
setSearchParams({ q: query, page: '1' });
};
const query = searchParams.get('q') || '';
const page = searchParams.get('page') || '1';
return (
<div>
<input
value={query}
onChange={(e) => handleSearch(e.target.value)}
placeholder="Search..."
/>
<p>Results for: {query} (Page {page})</p>
</div>
);
};
// Vue Query Param Hook
import { useRoute, useRouter } from 'vue-router';
import { computed } from 'vue';
export function useQueryParams() {
const route = useRoute();
const router = useRouter();
const query = computed(() => route.query.q as string || '');
const page = computed(() => parseInt(route.query.page as string) || 1);
const setQuery = (q: string) => {
router.push({ query: { q, page: '1' } });
};
return { query, page, setQuery };
}React Router v6
React Router v6
// App.tsx
import { BrowserRouter, Routes, Route, Navigate } from 'react-router-dom';
import { Layout } from './components/Layout';
import { Home } from './pages/Home';
import { NotFound } from './pages/NotFound';
import { useAuth } from './hooks/useAuth';
import React from 'react';
// Lazy loaded components
const Dashboard = React.lazy(() => import('./pages/Dashboard'));
const UserProfile = React.lazy(() => import('./pages/UserProfile'));
const Settings = React.lazy(() => import('./pages/Settings'));
// Protected route wrapper
const ProtectedRoute: React.FC<{ children: React.ReactNode }> = ({ children }) => {
const { isAuthenticated } = useAuth();
if (!isAuthenticated) {
return <Navigate to="/login" replace />;
}
return <>{children}</>;
};
export const App: React.FC = () => {
return (
<BrowserRouter>
<Routes>
<Route path="/" element={<Layout />}>
<Route index element={<Home />} />
<Route
path="dashboard"
element={
<ProtectedRoute>
<React.Suspense fallback={<div>Loading...</div>}>
<Dashboard />
</React.Suspense>
</ProtectedRoute>
}
/>
<Route
path="users/:id"
element={
<React.Suspense fallback={<div>Loading...</div>}>
<UserProfile />
</React.Suspense>
}
/>
<Route path="settings" element={<Settings />} />
<Route path="*" element={<NotFound />} />
</Route>
</Routes>
</BrowserRouter>
);
};
// Usage in components
import { useParams, useNavigate, useSearchParams } from 'react-router-dom';
const UserProfile: React.FC = () => {
const { id } = useParams<{ id: string }>();
const navigate = useNavigate();
const [searchParams] = useSearchParams();
const tab = searchParams.get('tab') || 'profile';
return (
<div>
<h1>User {id}</h1>
<p>Tab: {tab}</p>
<button onClick={() => navigate('/')}>Go Home</button>
<button onClick={() => navigate('?tab=settings')}>Settings</button>
</div>
);
};Route Transition Effects
Route Transition Effects
/* CSS Transition */
.fade-enter-active,
.fade-leave-active {
transition: opacity 0.3s ease;
}
.fade-enter-from,
.fade-leave-to {
opacity: 0;
}
.slide-enter-active,
.slide-leave-active {
transition: transform 0.3s ease;
}
.slide-enter-from {
transform: translateX(-100%);
}
.slide-leave-to {
transform: translateX(100%);
}Vue Router 4
Vue Router 4
// router/index.ts
import { createRouter, createWebHistory, RouteRecordRaw } from "vue-router";
import { useAuthStore } from "@/stores/auth";
const routes: RouteRecordRaw[] = [
{
path: "/",
component: () => import("@/views/Home.vue"),
meta: { title: "Home" },
},
{
path: "/login",
component: () => import("@/views/Login.vue"),
meta: { title: "Login", requiresGuest: true },
},
{
path: "/dashboard",
component: () => import("@/views/Dashboard.vue"),
meta: { title: "Dashboard", requiresAuth: true },
children: [
{
path: "users",
component: () => import("@/views/Users.vue"),
meta: { title: "Users" },
},
{
path: "analytics",
component: () => import("@/views/Analytics.vue"),
meta: { title: "Analytics" },
},
],
},
{
path: "/users/:id",
component: () => import("@/views/UserDetail.vue"),
meta: { title: "User Details", requiresAuth: true },
},
{
path: "/:pathMatch(.*)*",
component: () => import("@/views/NotFound.vue"),
meta: { title: "Not Found" },
},
];
const router = createRouter({
history: createWebHistory(import.meta.env.BASE_URL),
routes,
});
// Navigation guards
router.beforeEach((to, from, next) => {
const authStore = useAuthStore();
// Update page title
document.title = (to.meta.title as string) || "App";
// Check authentication
if (to.meta.requiresAuth && !authStore.isAuthenticated) {
next("/login");
} else if (to.meta.requiresGuest && authStore.isAuthenticated) {
next("/dashboard");
} else {
next();
}
});
export default router;
// main.ts
import { createApp } from "vue";
import App from "./App.vue";
import router from "./router";
createApp(App).use(router).mount("#app");// Component: [Name]
// TODO: Customize for your framework (React, Vue, Svelte, etc.)
import React from 'react';
interface Props {
// TODO: Define props
}
export function ComponentName({ }: Props) {
// TODO: Add state and effects
return (
<div>
{/* TODO: Add component markup */}
</div>
);
}
Related skills
FAQ
Which frontend frameworks does frontend-routing target?
frontend-routing targets React, Vue, or similar SPA frameworks when setting up client-side or hybrid routing. The skill covers nested layouts, guards, and deep links during scaffold or extension work.
What routing concerns does frontend-routing address?
frontend-routing addresses client-side or hybrid routing configuration, nested layout composition, route guards for protected pages, and deep-link behavior so URLs remain shareable in single-page applications.