Skip to content
Merged
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
20 changes: 4 additions & 16 deletions docs/components/nav-link.md
Original file line number Diff line number Diff line change
Expand Up @@ -84,29 +84,17 @@ You can pass a render prop as children to customize the content of the `<NavLink

The `end` prop changes the matching logic for the `active` and `pending` states to only match to the "end" of the NavLink's `to` path. If the URL is longer than `to`, it will no longer be considered active.

Without the end prop, this link is always active because every URL matches `/`.

```tsx
<NavLink to="/">Home</NavLink>
```

To match the URL "to the end" of `to`, use `end`:

```tsx
<NavLink to="/" end>
Home
</NavLink>
```

Now this link will only be active at `"/"`. This works for paths with more segments as well:

| Link | URL | isActive |
| ----------------------------- | ------------ | -------- |
| `<NavLink to="/tasks" />` | `/tasks` | true |
| `<NavLink to="/tasks" />` | `/tasks/123` | true |
| `<NavLink to="/tasks" end />` | `/tasks` | true |
| `<NavLink to="/tasks" end />` | `/tasks/123` | false |

**A note on links to the root route**

`<NavLink to="/">` is an exceptional case because _every_ URL matches `/`. To avoid this matching every single route by default, it effectively ignores the `end` prop and only matches when you're at the root route.

## `caseSensitive`

Adding the `caseSensitive` prop changes the matching logic to make it case sensitive.
Expand Down
36 changes: 36 additions & 0 deletions packages/react-router-dom/__tests__/nav-link-active-test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -317,6 +317,42 @@ describe("NavLink", () => {
expect(anchors.map((a) => a.props.className)).toEqual(["active", ""]);
});

it("matches the root route with or without the end prop", () => {
let renderer: TestRenderer.ReactTestRenderer;
TestRenderer.act(() => {
renderer = TestRenderer.create(
<MemoryRouter>
<Routes>
<Route index element={<NavLink to="/">Root</NavLink>} />
</Routes>
</MemoryRouter>
);
});

let anchor = renderer.root.findByType("a");
expect(anchor.props.className).toMatch("active");

TestRenderer.act(() => {
renderer = TestRenderer.create(
<MemoryRouter>
<Routes>
<Route
index
element={
<NavLink to="/" end>
Root
</NavLink>
}
/>
</Routes>
</MemoryRouter>
);
});

anchor = renderer.root.findByType("a");
expect(anchor.props.className).toMatch("active");
});

it("does not automatically apply to root non-layout segments", () => {
let renderer: TestRenderer.ReactTestRenderer;
TestRenderer.act(() => {
Expand Down