Client-side routing
Cimpress UI components such as Link
, Menu
, and many others support rendering elements as links that perform navigation.
Each component that supports link behavior accepts the href
prop, which causes the component to render an <a>
element.
Other link DOM props such as target
and download
are also supported.
<Link href="https://example.com/" target="_blank"> Open example site</Link>
By default, links perform native browser navigation when they are interacted with.
However, many apps and frameworks use client-side routers to avoid a full page reload when navigating between pages.
The RouterProvider
component configures all Cimpress UI components within it to navigate using the client-side router you provide.
Set this up once in the root of your app, and any Cimpress UI component with the href
prop will automatically navigate using your router.
Note that external links to different origins will not trigger client-side routing, and will use native browser navigation.
Additionally, if the link has a target other than '_self'
, uses the download
attribute, or the user presses modifier keys such as Command or Alt to change the default behavior,
browser native navigation will occur instead of client-side routing.
All Cimpress UI link components accept a routerOptions
prop, which is an object passed to the client-side router’s navigate
function as the second argument.
This can be used to control any router-specific behaviors, such as scrolling, replacing instead of pushing to the history, etc.
<Link href="/login" routerOptions={{ replace: true }}> Login</Link>
Integrating client-side routing with Cimpress UI
Section titled “Integrating client-side routing with Cimpress UI”-
Wrap your application in Cimpress UI’s
RouterProvider
:src/app.tsx import { RouterProvider } from '@cimpress-ui/react';export function App() {return ({/* ... */}<RouterProvider>{/* ... */}</RouterProvider>);} -
Obtain a function from your routing framework that performs client-side navigation programmatically. Pass this function to
RouterProvider
in thenavigate
prop:src/app.tsx import { RouterProvider } from '@cimpress-ui/react';import { useNavigate } from 'your-router';export function App() {const navigate = useNavigate();return (<RouterProvider><RouterProvider navigate={navigate}>{/* ... */}</RouterProvider>);} -
If your router supports converting router-specific
href
s to native HTMLhref
s, pass the function that does this toRouterProvider
in theuseHref
prop:src/app.tsx import { RouterProvider } from '@cimpress-ui/react';import { useNavigate } from 'your-router';import { useNavigate, useHref } from 'your-router';export function App() {const navigate = useNavigate();return (<RouterProvider navigate={navigate}><RouterProvider navigate={navigate} useHref={useHref}>{/* ... */}</RouterProvider>);} -
Configure the
RouterConfig
type globally using a type provided by your router. This ensures type safety and autocomplete support for all link components.src/declarations.d.ts import type { Href, RouterOptions } from 'your-router';declare module '@cimpress-ui/react' {interface RouterConfig {href: Href;routerOptions: RouterOptions;}}
Framework-specific examples
Section titled “Framework-specific examples”React Router
Section titled “React Router”The useNavigate
hook from react-router-dom
returns a navigate
function that you can pass to RouterProvider
.
The useHref
hook can also be provided if you’re using React Router’s basename
option.
Make sure that:
- The component that calls
useNavigate
and rendersRouterProvider
is inside the router component (e.g.BrowserRouter
), so that it has access to React Router’s internal context. - The React Router’s
Routes
element should be defined inside Cimpress UI’sRouterProvider
so that links inside the rendered routes have access to the router.
import { StrictMode } from 'react';import { createRoot } from 'react-dom/client';import { BrowserRouter } from 'react-router-dom';import App from './app.js';
import '@fontsource-variable/open-sans/wght.css';import '@fontsource-variable/open-sans/wght-italic.css';import '@cimpress-ui/react/styles.css';
createRoot(document.getElementById('root')!).render( <StrictMode> <App /> <BrowserRouter> <App /> </BrowserRouter> </StrictMode>,);
import { Route, Routes } from 'react-router-dom';import { Route, Routes, useHref, useNavigate } from 'react-router-dom';import { RouterProvider } from '@cimpress-ui/react';import { HomePage } from './pages/home-page.js';
export function App() { const navigate = useNavigate();
return ( <RouterProvider navigate={navigate} useHref={useHref}> {/* ... */} <Routes> <Route path="/" element={<HomePage />} /> {/* ... */} </Routes> </RouterProvider> );}
import type { NavigateOptions } from 'react-router-dom';
declare module '@cimpress-ui/react' { interface RouterConfig { routerOptions: NavigateOptions; }}
Remix uses React Router under the hood, so the same useNavigate
and useHref
hooks described above also work in Remix apps.
RouterProvider
should be rendered at the root of each page that includes Cimpress UI links, or in the root route to add it to all pages.
Next.js app router
Section titled “Next.js app router”The useRouter
hook from next/navigation
returns a router object that can be used to perform navigation.
RouterProvider
should be rendered from a client component at the root of each page or layout that includes Cimpress UI links.
'use client';
import { useRouter } from 'next/navigation';import { RouterProvider } from '@cimpress-ui/react';
export default function RootLayout({ children }) { const router = useRouter();
return ( <html> <body> {children} <RouterProvider navigate={router.push}> {children} </RouterProvider> </body> </html> );}
import { useRouter } from 'next/navigation';
declare module '@cimpress-ui/react' { interface RouterConfig { routerOptions: NonNullable< Parameters<ReturnType<typeof useRouter>['push']>[1] >; }}
If you are using the basePath
configuration option, you’ll need to configure an environment variable to access it.
Then, provide a custom useHref
function to prepend basePath
to the href
for all links.
const basePath = '...';
const nextConfig = { basePath, env: { BASE_PATH: basePath }};
'use client';
import { useRouter } from 'next/navigation';import { RouterProvider } from '@cimpress-ui/react';
const useHref = (href: string) => process.env.BASE_PATH + href;
export default function RootLayout({ children }) { const router = useRouter();
return ( <html> <body> <RouterProvider navigate={router.push}> <RouterProvider navigate={router.push} useHref={useHref}> {children} </RouterProvider> </body> </html> );}
Next.js pages router
Section titled “Next.js pages router”The useRouter
hook from next/router
returns a router object that can be used to perform navigation.
RouterProvider
should be rendered at the root of each page or layout that includes Cimpress UI links, or in pages/_app.tsx
to add it to all pages.
import type {AppProps} from 'next/app';import {useRouter} from 'next/router'import {RouterProvider} from '@cimpress-ui/react';
export default function MyApp({ Component, pageProps }: AppProps) { const router = useRouter();
return ( <RouterProvider navigate={(href, options) => router.push(href, undefined, options)} > <Component {...pageProps} /> </RouterProvider> );}
import type { NextRouter } from 'next/router';
declare module '@cimpress-ui/react' { interface RouterConfig { routerOptions: NonNullable< Parameters<NextRouter['push']>[2] >; }}
If you are using the basePath
configuration option, provide a useHref
prop to RouterProvider
to prepend it to links automatically.
import type { AppProps } from 'next/app';import { useRouter } from 'next/router';import { RouterProvider } from '@cimpress-ui/react';
export default function MyApp({ Component, pageProps }: AppProps) { const router = useRouter();
return ( <RouterProvider navigate={(href, options) => router.push(href, undefined, options)} useHref={(href: string) => router.basePath + href} > <Component {...pageProps} /> </RouterProvider> );}