Why React NavLink Active State Breaks in SPFx (and the Only Workaround That Works)
After days of regression, refactoring, and second-guessing React itself, the truth finally emerged: the problem was never React — it was SharePoint.
🧩 The Problem
When building a custom sidebar or header using an SPFx Application Customizer, you may expect:
-
NavLinkto stay active -
useLocation()to update on navigation -
React Router to behave like an SPA
None of that reliably works in modern SharePoint.
Symptoms you will see:
-
Menu highlights only on the second click
-
Active state disappears on page navigation
-
useLocation()doesn’t update -
React state resets randomly
-
URLs change without React knowing
Why This Happens (The Root Cause)
Modern SharePoint does NOT do full page reloads.
Instead, it uses:
-
Partial page navigation
-
History API manipulation
-
Internal routing outside React
This means:
-
React Router never receives navigation events
-
The page URL updates, but your extension is unaware
-
NavLinkactive logic silently fails
Note: SPFx Application Customizers are not SPAs
Why Common Solutions Fail
| Attempt | Why it fails |
|---|---|
NavLink isActive | No router events |
useLocation() | URL changes outside React |
<a> tags | Full reload breaks UI |
basename tricks | SharePoint rewrites paths |
force re-render | Page DOM replaced |
✅ The Only Reliable Approach (Workaround)
Instead of reacting to routing events that don’t exist,
watch the browser URL directly and update the DOM manually.
Yes — this breaks “pure React” rules.
But in SPFx Application Customizers, this is the correct approach.
🛠️ Working Solution: URL Polling + DOM Class Swap
🎯 Why This Works
-
SharePoint always updates
location.href -
We bypass React Router entirely
-
DOM survives partial navigation
-
Works for:
-
EN / AR URLs
-
Deep SitePages
-
Document libraries
-
RTL layouts
-
⚠️ Is This Bad Practice?
In normal React apps → Yes ❌
In SPFx Application Customizers → No ✅
Microsoft’s own SharePoint UI uses:
-
Observers
-
URL polling
-
Direct DOM mutation
This is expected in extensions.
🧠 Lessons Learned
-
SPFx ≠ SPA
-
React Router ≠ SharePoint Router
-
Purity must sometimes yield to reality
-
If highlighting works on 2nd click → URL timing issue
🏁 Final Thoughts
If you are building:
-
Custom sidebars
-
Mega menus
-
Headers
-
Language switchers
Do not fight SharePoint’s navigation model.
Observe it.
This workaround saved days of regression — and will save yours too.
No comments:
Post a Comment
Note: Only a member of this blog may post a comment.