Recommended resources
The freely available resources this lesson will direct you to.
Hello! Welcome to the fifth lesson in our course on mastering TanStack Start and Router.
In our last lesson, we focused on defining routes with typed path parameters and search parameters. You learned how to use file-system conventions like $param and the validateSearch option with Zod to create a type-safe foundation for your application's routes.
Lesson 5: Typed Navigation
Today's Goal:
This lesson directly addresses the learning outcome: Implement typed navigation using the Link component and useNavigate hook. We will build upon the typed route definitions from the previous lesson to see how TanStack Router provides a fully type-safe navigation experience, catching potential URL errors at compile time.
As an experienced front-end developer, you're well-acquainted with client-side routing. Today, we'll focus on how TanStack Router elevates this by integrating your route schemas directly into the navigation APIs, effectively preventing you from creating links to invalid or incomplete URLs.
What we will cover:
- Declarative Navigation: Using the type-safe
<Link>component for user-driven navigation. - Imperative Navigation: Using the
useNavigatehook for programmatic navigation within side effects. - Navigating with Parameters: How to correctly pass path and search parameters when creating links or navigating programmatically.
1. Declarative Navigation with the <Link> Component
The most common way to allow users to navigate your application is with links. TanStack Router provides a <Link> component that acts as a type-safe wrapper around a standard <a> tag.
The key benefit is that its props—to, params, and search—are all typed based on the route tree you've built. If you try to link to a route without providing its required parameters, TypeScript will immediately flag it as an error.
Let's start with a video that demonstrates the basic usage and its type-safe autocompletion.
Complete TanStack Router Tutorial - Build Type-Safe React Apps with File-Based Routing
This brief clip from the 'Complete TanStack Router Tutorial' by Code Genix shows the initial setup of navigation using the Link component. Notice the autocompletion provided for the to prop, which is the first sign of the router's type safety.
Watch from 12:01 to 13:35. Pay attention to how the to prop offers suggestions for valid routes and how activeProps can be used for styling.
Diving Deeper into <Link> Props
The <Link> component is versatile. The official documentation provides an excellent overview of its capabilities. We'll focus on the most critical props for creating dynamic, typed links.
Navigation | TanStack Router React Docs
Please read the following sections from the official TanStack Router documentation on 'Navigation'. This will give you a solid understanding of the different ways you can use the Link component.
In the ' Component' section, please read the subsections: 'Absolute Links', 'Dynamic Links', 'Relative Links', and 'Search Param Links'. Focus on how the params and search props are used to construct a complete, typed URL.
Key Link Props Summary:
to: The path of the route to navigate to. It's type-safe and will be one of the valid paths from your route tree.params: An object containing the path parameters for a dynamic route. For a route like/posts/$postId, you must provide{ postId: 'some-id' }.search: An object for the search parameters. It can also be a function(prev) => ({ ...prev, newParam: 'value' })to update existing search params without losing others.from: The route path you are linking from. This is powerful for relative navigation in nested routes, as it allows the router to automatically infer and carry over parent path parameters.
Practical Example: Nested Routes and the from Prop
The from prop is particularly useful. When you're deep in a nested route (e.g., /users/123/invoices/456), creating a link to a sibling route (e.g., /users/123/settings) can be verbose if you have to supply the userId param every time. By specifying from, you tell the router to inherit the necessary params.
This video segment provides an excellent demonstration of navigating to routes with path parameters and shows the from prop in action.
Complete TanStack Router Tutorial - Build Type-Safe React Apps with File-Based Routing
This clip continues the 'Complete TanStack Router Tutorial' and demonstrates creating links to dynamic routes that require path parameters. It culminates in a great example of why the from prop is so useful.
Watch from 29:04 to 34:08. Observe how the params prop is required when linking to the dynamic country route. Then, pay close attention to the explanation of the from prop around the 33:00 mark, where it solves the problem of re-supplying the country parameter for a nested link.
2. Imperative Navigation with the useNavigate Hook
While <Link> is perfect for UI elements that a user clicks, you often need to trigger navigation programmatically. This is common after a side effect, such as a successful form submission or API call. For this, TanStack Router provides the useNavigate hook.
Navigation | TanStack Router React Docs
First, read the documentation's introduction to the useNavigate hook. It clearly explains its purpose and when to use it over the <Link> component.
Read the section 'useNavigate'. The key takeaway is that this is for handling side-effect navigations.
The useNavigate hook returns a navigate function. This function accepts an options object that is, once again, fully typed with the same to, params, and search properties as the <Link> component.
useNavigate in Action
A classic use case for useNavigate is redirecting a user after they log in. The following video shows exactly this scenario.
Complete TanStack Router Tutorial - Build Type-Safe React Apps with File-Based Routing
This final clip from the tutorial shows a practical implementation of useNavigate to redirect a user after a successful login, including passing along search params to return them to their intended page.
Watch from 01:09:51 to 01:10:43. Note how useNavigate is called to get the navigate function, which is then used inside the login logic.
For a quick reference of the different ways you can call the navigate function, the API documentation provides clear examples.
useNavigate hook | TanStack Router React Docs
The official API documentation for useNavigate provides several concise examples of its usage. This is a good reference to review.
Review the code snippets in the 'Examples' section. Notice the different combinations of options you can pass to the navigate function, such as to, search, hash, and state.
3. Practical Application: Tying It All Together
Let's revisit the example from our last lesson: a product page with tabs for "details" and "reviews" controlled by a search parameter.
Route: /products/$productId
Search Schema: tab can be 'details' or 'reviews', defaulting to 'details'.
Here’s how you would implement navigation for this component:
import { createFileRoute, Link, useNavigate } from '@tanstack/react-router';
import { z } from 'zod';
const productSearchSchema = z.object({
tab: z.enum(['details', 'reviews']).default('details').catch('details'),
});
export const Route = createFileRoute('/products/$productId')({
validateSearch: productSearchSchema,
component: ProductComponent,
});
function ProductComponent() {
const { productId } = Route.useParams();
const { tab } = Route.useSearch();
const navigate = useNavigate();
const handleSave = async () => {
// Pretend to save data...
console.log('Saving product data...');
await new Promise(res => setTimeout(res, 1000));
// On success, navigate back to the main products list.
// This is a perfect use case for useNavigate.
navigate({ to: '/products' });
};
return (
<div>
<h1>Product ID: {productId}</h1>
{/* Navigation using the Link component to change search params */}
<div style={{ display: 'flex', gap: '1rem', marginBottom: '1rem' }}>
<Link
to="/products/$productId"
params={{ productId }}
search={{ tab: 'details' }}
activeProps={{ style: { fontWeight: 'bold' } }}
>
Details
</Link>
<Link
to="/products/$productId"
params={{ productId }}
search={{ tab: 'reviews' }}
activeProps={{ style: { fontWeight: 'bold' } }}
>
Reviews
</Link>
</div>
{/* Render content based on the tab */}
{tab === 'details' && <div>Showing product details...</div>}
{tab === 'reviews' && <div>Showing product reviews...</div>}
<button onClick={handleSave} style={{ marginTop: '1rem' }}>
Save and Return to List
</button>
</div>
);
}
In this example:
- We use two
<Link>components for the tabs. They navigate to the same path but provide differentsearchparameters. Notice we must also provide the requiredproductIdto theparamsprop. - The
useNavigatehook is used inside an event handler (handleSave) to programmatically redirect the user after an action is complete.
Conclusion
You have now learned the two primary methods for handling navigation in TanStack Router. By leveraging the typed route definitions from our previous lesson, both the <Link> component and the useNavigate hook provide a development experience that prevents a whole class of routing errors.
Key Takeaways:
- Declarative Navigation: Use the
<Link>component for any navigation that the user directly initiates via the UI. It is type-safe and renders a proper<a>tag. - Imperative Navigation: Use the
useNavigatehook to programmatically trigger navigation as a result of a side effect (e.g., API calls, form submissions). - Type-Safe Parameters: Both methods require you to provide correctly typed
paramsandsearchobjects, ensuring you can't create an invalid link. - The
fromProp: Use this on<Link>oruseNavigateto simplify relative navigation in nested routes by inheriting parent parameters.
Next Lesson Preview:
With a solid grasp of defining routes and navigating between them, we are ready to tackle more complex UI structures. In the next lesson, we will "Implement nested routes and layout routes for shared UI." You'll learn how to create persistent layouts (like sidebars and headers) that wrap around changing page content, a fundamental pattern in modern web applications.