āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā ā š shadcn/directory/clerk/clerk-docs/guides/development/add-react-router ā āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā
āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā
ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā
<TutorialHero exampleRepo={[ { title: "Clerk Chrome Extension Repo", link: "https://github.com/clerk/clerk-chrome-extension-quickstart" } ]} beforeYouStart={[ { title: "Set up a Clerk application", link: "/docs/getting-started/quickstart/setup-clerk", icon: "clerk" }, { title: "Add auth and user management to your Chrome Extension with Clerk", link: "/docs/chrome-extension/getting-started/quickstart", icon: "react" }, ]} />
This tutorial demonstrates how to integrate React Router into your Chrome Extension application. It assumes you're using Plasmo to build your Chrome Extension.
<Steps> ## Install `react-router`React Router is a lightweight, fully-featured routing library. To install it in your project, run the following command:
pnpm add react-router
[!IMPORTANT] This guide assumes you're using Plasmo to build your Chrome Extension, so you must use
pnpmas your package manager.
src/ directory, create a popup/ directory.popup/ directory, create a routes/ directory.routes/ directory, create the home.tsx, sign-in.tsx, sign-up.tsx, and settings.tsx files.<CodeBlockTabs options={["Home", "Sign-in", "Sign-up", "Settings"]}>
tsx {{ filename: 'src/popup/routes/home.tsx' }} export const Home = () => { return ( <> <h1>Clerk + Chrome Extension + React Router</h1> </> ) }
```tsx {{ filename: 'src/popup/routes/sign-in.tsx' }}
import { SignIn } from '@clerk/chrome-extension'
export const SignInPage = () => {
return (
<>
<p>Sign In</p>
<SignIn routing="virtual" />
</>
)
}
```
```tsx {{ filename: 'src/popup/routes/sign-up.tsx' }}
import { SignUp } from '@clerk/chrome-extension'
export const SignUpPage = () => {
return (
<>
<p>Sign Up</p>
<SignUp routing="virtual" />
</>
)
}
```
```tsx {{ filename: 'src/popup/routes/settings.tsx' }}
import { UserProfile } from '@clerk/chrome-extension'
export const Settings = () => {
return (
<>
<h1>Settings</h1>
<UserProfile routing="virtual" />
</>
)
}
```
</CodeBlockTabs>
src/popup.tsx file.src/popup/ directory, create a layouts/ directory.layouts/ directory, create a root-layout.tsx file.root-layout.tsx file, paste the following code to create a layout for your app.
<Outlet /> component from react-router. This behaves similar to {children} in Next.js or more generic React components.<UserButton /> component and a link to the /settings page, which renders Clerk's <UserProfile /> component. Clerk's <SignedIn> and <SignedOut> control components determine what's displayed based on the user's authentication state.<CodeBlockTabs options={["Root Layout"]}> ```tsx {{ filename: 'src/popup/layouts/root-layout.tsx' }} import { Link, Outlet, useNavigate } from 'react-router' import { ClerkProvider, SignedIn, SignedOut, UserButton } from '@clerk/chrome-extension'
const PUBLISHABLE_KEY = process.env.PLASMO_PUBLIC_CLERK_PUBLISHABLE_KEY
if (!PUBLISHABLE_KEY) {
throw new Error('Please add the PLASMO_PUBLIC_CLERK_PUBLISHABLE_KEY to the .env.development file')
}
export const RootLayout = () => {
const navigate = useNavigate()
return (
<ClerkProvider
routerPush={(to) => navigate(to)}
routerReplace={(to) => navigate(to, { replace: true })}
publishableKey={PUBLISHABLE_KEY}
afterSignOutUrl="/"
>
<div className="plasmo-w-[785px] plasmo-h-[600px]">
<main>
<Outlet />
</main>
<footer>
<SignedIn>
<Link to="/settings">Settings</Link>
<UserButton />
</SignedIn>
<SignedOut>
<Link to="/">Home</Link>
<Link to="/sign-in">Sign In</Link>
<Link to="/sign-up">Sign Up</Link>
</SignedOut>
</footer>
</div>
</ClerkProvider>
)
}
```
</CodeBlockTabs>
createMemoryRouterReact Router's createMemoryRouter is a router that uses memory to store the state of the router instead of the browser's history. This is useful for creating a router in a non-browser environment like a Chrome Extension.
src/popup/ directory, create an index.tsx file.index.tsx file, paste the following code to configure your routes with createMemoryRouter.import React from 'react'
import '../style.css'
import { createMemoryRouter, RouterProvider } from 'react-router'
import { RootLayout } from './layouts/root-layout'
import { Home } from './routes/home'
import { Settings } from './routes/settings'
import { SignInPage } from './routes/sign-in'
import { SignUpPage } from './routes/sign-up'
const router = createMemoryRouter([
{
// Wraps the entire app in the root layout
element: <RootLayout />,
// Mounted where the <Outlet /> component is inside the root layout
children: [
{ path: '/', element: <Home /> },
{ path: '/sign-in', element: <SignInPage /> },
{ path: '/sign-up', element: <SignUpPage /> },
{ path: '/settings', element: <Settings /> },
],
},
])
export default function PopupIndex() {
return <RouterProvider router={router} />
}
pnpm dev
<SignUp /> component is rendered.<SignIn /> component is rendered. Sign in with your account. You'll be redirected to the home page and the footer will display the Settings link and the <UserButton /> component.<UserButton /> component to open the user menu.<UserProfile /> component is rendered.
</Steps>
ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā
āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā