Skip to content

Fix/79141 escape parallel routes docs #79450

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 4 commits into
base: canary
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,48 @@ For example, considering a dashboard, you can use parallel routes to simultaneou
height="942"
/>

> **Good to know**:
>
> - Before learning about slots, note that literal `@` symbols in routes require [special handling](#using-literal--symbols-in-routes).

## Using literal @ symbols in routes

When you need to use an `@` symbol in your route path (not as a parallel route segment), you have several options:

### URL Encoding

Replace `@` with its URL-encoded equivalent `%40`: app/[%40grida]/pixel-grid/page.tsx

This will match routes like `/@grida/pixel-grid`.

### Dynamic Segments

Create a dynamic segment that specifically matches your pattern:

```
// app/[@grida]/pixel-grid/page.tsx
export default function Page({
params,
}: {
params: { "@grida": string }
}) {
// Your page content
}
```

### Middleware rewrites

For more complex cases, middleware can be used to rewrite incoming requests:

```
// middleware.ts
export function middleware(request: NextRequest) {
if (request.nextUrl.pathname.startsWith('/@grida')) {
return NextResponse.rewrite(new URL('/@grida-handler', request.url))
}
}
```

## Slots

Parallel routes are created using named **slots**. Slots are defined with the `@folder` convention. For example, the following file structure defines two slots: `@analytics` and `@team`:
Expand Down
1 change: 0 additions & 1 deletion examples/cms-contentful/.env.local.example
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
CONTENTFUL_SPACE_ID=
CONTENTFUL_ACCESS_TOKEN=
CONTENTFUL_PREVIEW_ACCESS_TOKEN=
CONTENTFUL_PREVIEW_SECRET=
CONTENTFUL_REVALIDATE_SECRET=
24 changes: 2 additions & 22 deletions examples/cms-contentful/app/api/draft/route.ts
Original file line number Diff line number Diff line change
@@ -1,22 +1,2 @@
import { draftMode } from "next/headers";
import { redirect } from "next/navigation";
import { getPreviewPostBySlug } from "../../../lib/api";

export async function GET(request: Request) {
const { searchParams } = new URL(request.url);
const secret = searchParams.get("secret");
const slug = searchParams.get("slug");

if (secret !== process.env.CONTENTFUL_PREVIEW_SECRET) {
return new Response("Invalid token", { status: 401 });
}

const post = await getPreviewPostBySlug(slug);

if (!post) {
return new Response("Invalid slug", { status: 401 });
}

draftMode().enable();
redirect(`/posts/${post.slug}`);
}
//@ts-ignore
export { enableDraftHandler as GET } from "@contentful/vercel-nextjs-toolkit/app-router";
1 change: 1 addition & 0 deletions examples/cms-contentful/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
"dependencies": {
"@contentful/rich-text-react-renderer": "^15.17.1",
"@contentful/rich-text-types": "^16.2.1",
"@contentful/vercel-nextjs-toolkit": "latest",
"@tailwindcss/typography": "0.5.9",
"@types/node": "^20.5.0",
"@types/react": "^18.2.20",
Expand Down