|
| 1 | +# SPFx Global Navigation Header Customizer |
| 2 | + |
| 3 | +A global header and footer solution for SharePoint Online modern portals, built using the SharePoint Framework (SPFx), React, and Fluent UI React Components (v9). It connects to either the SharePoint Term Store (Managed Navigation) or a JSON file hosted in your site assets library, allowing you to manage navigation links and configurations dynamically. |
| 4 | + |
| 5 | +## Summary |
| 6 | + |
| 7 | +This extension mounts into the SharePoint Online `Top` placeholder to render a responsive global header with a customizable brand area, desktop mega-menu navigation, and a mobile drawer. It includes built-in tools for search, profile info, bookmarks, notifications, and accessibility controls. You can also enable an optional HTML footer in the `Bottom` placeholder and inject SEO metadata dynamically from your navigation terms. |
| 8 | + |
| 9 | +## Compatibility |
| 10 | + |
| 11 | +| :warning: Important | |
| 12 | +|:---------------------------| |
| 13 | +| Every SPFx version is compatible with specific versions of Node.js. To compile this project, ensure that the version of Node.js on your workstation matches the version listed below. | |
| 14 | +| Refer to <https://aka.ms/spfx-matrix> for more information on SPFx compatibility. | |
| 15 | + |
| 16 | +This sample is optimally compatible with the following environment configuration: |
| 17 | + |
| 18 | + |
| 19 | + |
| 20 | + |
| 21 | + |
| 22 | + |
| 23 | + |
| 24 | + |
| 25 | +## Applies to |
| 26 | + |
| 27 | +- SharePoint Online |
| 28 | +- SharePoint Framework (SPFx) v1.23.2 |
| 29 | + |
| 30 | +## Contributors |
| 31 | + |
| 32 | +- [Nicolas Kheirallah](https://github.com/NicolasKheirallah) |
| 33 | + |
| 34 | +## Version history |
| 35 | + |
| 36 | +| Version | Date | Comments | |
| 37 | +| :--- | :--- | :--- | |
| 38 | +| **2.1.0** | 2026-07-07 | Refactored accessibility features (disclosure pattern), debounced suite-bar MutationObserver, resolved React 18 async unmounting race conditions, and stripped unnecessary comments. | |
| 39 | +| **2.0.0** | 2026-06-15 | Upgraded project to SPFx v1.23.2, React 18, and Fluent UI v9. | |
| 40 | + |
| 41 | +## Minimal Path to Awesome |
| 42 | + |
| 43 | +1. Clone this repository. |
| 44 | +2. Ensure you are using Node.js v22 (e.g. `nvm use 22`). |
| 45 | +3. Run `npm install` to restore dependencies. |
| 46 | +4. Run `npm run build` to compile and package the solution. |
| 47 | +5. Configure your local debugging parameters in `config/serve.json`, then run: |
| 48 | + |
| 49 | + ```bash |
| 50 | + npm run start |
| 51 | + ``` |
| 52 | + |
| 53 | +## Tech Stack |
| 54 | + |
| 55 | +- SharePoint Framework `1.23.2` |
| 56 | +- Heft build toolchain |
| 57 | +- TypeScript `~5.8.0` |
| 58 | +- React `18.2.0` |
| 59 | +- ReactDOM `18.2.0` |
| 60 | +- Fluent UI React Components (v9) `^9.74.3` |
| 61 | +- PnPjs v4 `^4.20.0` |
| 62 | +- ESLint-based linting (SPFx config) |
| 63 | + |
| 64 | +Node requirement: `>=22.14.0 <23.0.0` |
| 65 | + |
| 66 | +--- |
| 67 | + |
| 68 | +## Detailed Technical Reference |
| 69 | + |
| 70 | +### Contents |
| 71 | + |
| 72 | +- [Overview](#overview) |
| 73 | +- [How it Works (Runtime Behavior)](#how-it-works-runtime-behavior) |
| 74 | +- [Key Technical Decisions](#key-technical-decisions) |
| 75 | +- [Configuration Reference](#configuration-reference) |
| 76 | +- [Provisioning via PowerShell](#provisioning-via-powershell) |
| 77 | +- [Accessibility & Security](#accessibility--security) |
| 78 | + |
| 79 | +--- |
| 80 | + |
| 81 | +## Screenshots |
| 82 | + |
| 83 | +### Navigation Features |
| 84 | + |
| 85 | +**Desktop Navigation with Mega-Menu** |
| 86 | + |
| 87 | + |
| 88 | +**Mobile Navigation Drawer** |
| 89 | + |
| 90 | + |
| 91 | + |
| 92 | +**Fullscreen Panel** |
| 93 | + |
| 94 | + |
| 95 | +### Admin Settings Panel |
| 96 | + |
| 97 | +**Admin Panel - Overview & Configuration** |
| 98 | + |
| 99 | + |
| 100 | + |
| 101 | + |
| 102 | +**Admin Panel - Styling & Colors** |
| 103 | + |
| 104 | + |
| 105 | + |
| 106 | + |
| 107 | +### User Experience |
| 108 | + |
| 109 | +**Settings Panel - User Profile** |
| 110 | + |
| 111 | + |
| 112 | +--- |
| 113 | + |
| 114 | +## Overview |
| 115 | + |
| 116 | +The solution mounts directly into SharePoint's placeholders to provide: |
| 117 | + |
| 118 | +- A responsive header bar that condenses automatically on scroll. |
| 119 | +- A desktop mega-menu supporting column groupings, featured items, and custom overview cards. |
| 120 | +- A mobile navigation panel (lazy-loaded to keep the main bundle light) with drill-down navigation. |
| 121 | +- An admin settings panel with a visual editor for navigation structures, color schemes, and feature flags. |
| 122 | +- An optional HTML footer that inherits the portal's theme variables. |
| 123 | + |
| 124 | +--- |
| 125 | + |
| 126 | +## How it Works (Runtime Behavior) |
| 127 | + |
| 128 | +### 1. Fast Initial Render |
| 129 | + |
| 130 | +To avoid layout shifts or blank areas during page load, the header checks for a cached snapshot of the navigation structure. If a cached version (5-minute TTL) is not available, it displays a fallback layout immediately while fetching the fresh structure asynchronously. |
| 131 | + |
| 132 | +### 2. Managed Navigation & Lazy Loading |
| 133 | + |
| 134 | +The Term Store navigation provider queries the SharePoint Term Store. Deeper sub-menus are hydrated lazily on demand when a user opens them, keeping initial payload sizes minimal. |
| 135 | + |
| 136 | +### 3. Dynamic Configuration Updates |
| 137 | + |
| 138 | +Configurations are resolved from three cascading sources (highest priority wins): |
| 139 | + |
| 140 | +1. A `settings.json` file uploaded to the site collection's document library. |
| 141 | +2. Deploy-time component properties (`ClientSideComponentProperties`). |
| 142 | +3. Built-in code defaults. |
| 143 | + |
| 144 | +This allows administrators to modify links, disable features, or change colors on the fly using the in-header editor without having to repackage or redeploy the `.sppkg` file. |
| 145 | + |
| 146 | +--- |
| 147 | + |
| 148 | +## Key Technical Decisions |
| 149 | + |
| 150 | +### 1. The Suite Bar Probe |
| 151 | + |
| 152 | +SharePoint Online does not expose the suite bar's current background color through the standard `ThemeProvider` API. To ensure the header blends in with the top Microsoft 365 bar, the engine probes the live DOM at runtime to read the computed background style. A debounced `MutationObserver` watches for slow-loading suite bar elements on initial load and schedules a paint as soon as it appears. |
| 153 | + |
| 154 | +### 2. Performance & Thread Optimization |
| 155 | + |
| 156 | +To prevent UI lag during page scrolls and window resizing: |
| 157 | + |
| 158 | +- Sub-components are wrapped in `React.memo()` to prevent unnecessary re-renders. |
| 159 | +- Context values destructured from raw properties are memoized to keep reference identities stable. |
| 160 | +- Resize calculations are throttled using animation frames. |
| 161 | + |
| 162 | +### 3. React 18 Async Unmounting |
| 163 | + |
| 164 | +SPFx customizers can be mounted and unmounted dynamically during client-side navigation. Since React 18's `root.unmount()` is asynchronous, host DOM elements are removed inside a microtask block to prevent detached nodes, memory leaks, and warning messages in the browser console. |
| 165 | + |
| 166 | +--- |
| 167 | + |
| 168 | +## Configuration Reference |
| 169 | + |
| 170 | +The Application Customizer accepts the following properties via `ClientSideComponentProperties` or `settings.json`: |
| 171 | + |
| 172 | +| Property | Description | Default | |
| 173 | +| :--- | :--- | :--- | |
| 174 | +| `homeUrl` | Target URL for the brand logo link. | Web absolute URL | |
| 175 | +| `logoUrl` | Absolute URL to the brand logo image. | None (no logo rendered) | |
| 176 | +| `logoAltText` | Accessibility label for the brand logo. | `"Logo"` | |
| 177 | +| `navigationSource` | Choose between `"taxonomy"` (Term Store) or `"jsonFile"` (Document library file). | `"taxonomy"` | |
| 178 | +| `termSetId` | Specific GUID of the term store set to load navigation from. | None | |
| 179 | +| `navigationFileName` | Custom filename for the JSON navigation source. | `"navigation.json"` | |
| 180 | +| `navigationFileFolder` | Server-relative folder path where configuration files are stored. | `"SiteAssets"` | |
| 181 | +| `features.adminSettingsEnabled` | Shows the settings gear icon in the header when the page is in edit mode. | `false` | |
| 182 | +| `features.footerEnabled` | Enables the bottom HTML footer placeholder. | `false` | |
| 183 | +| `features.themeSwitcherEnabled` | Enables the user-toggleable light/dark mode switcher. | `false` | |
| 184 | +| `features.searchEnabled` | Enables the search tool callout in the header. | `true` | |
| 185 | + |
| 186 | +### Color Overrides |
| 187 | + |
| 188 | +Admins can define a custom `colors` object in the properties. Any specified key will override the corresponding theme-derived value: |
| 189 | + |
| 190 | +- `chromeBackground`: Main header background color. |
| 191 | +- `chromeText`: Text and icon color on the header bar. |
| 192 | +- `accent`: Active underlines, border highlights, and brand markers. |
| 193 | +- `surface`: Dropdown panels and slide-out panel backgrounds. |
| 194 | +- `border`: Divider lines. |
| 195 | + |
| 196 | +--- |
| 197 | + |
| 198 | +## Provisioning via PowerShell |
| 199 | + |
| 200 | +We provide a PnP PowerShell script to provision a term store set with all the custom properties required by the extension. |
| 201 | + |
| 202 | +### Files |
| 203 | + |
| 204 | +- `scripts/navigation.json`: Defines the navigation hierarchy, SEO meta-tags, and custom layouts. |
| 205 | +- `scripts/Provision-Navigation.ps1`: Creates or updates the term set in your SharePoint Term Store. |
| 206 | + |
| 207 | +### Usage |
| 208 | + |
| 209 | +```powershell |
| 210 | +# Authenticate and run a dry-run test |
| 211 | +.\scripts\Provision-Navigation.ps1 -SiteUrl "https://contoso.sharepoint.com" -ClientId "YOUR_CLIENT_ID" -DryRun |
| 212 | +
|
| 213 | +# Provision into your tenant's Term Store |
| 214 | +.\scripts\Provision-Navigation.ps1 -SiteUrl "https://contoso.sharepoint.com" -ClientId "YOUR_CLIENT_ID" |
| 215 | +``` |
| 216 | + |
| 217 | +--- |
| 218 | + |
| 219 | +## Accessibility & Security |
| 220 | + |
| 221 | +### Accessibility (WCAG 2.2 AA) |
| 222 | + |
| 223 | +- **Disclosure Menus**: Top-level menu triggers use modern disclosure button patterns instead of nested menus. This keeps the tab order simple and matches screen-reader keyboard patterns. |
| 224 | +- **High Contrast**: Includes media overrides for `forced-colors: active` to match standard OS high-contrast themes. |
| 225 | +- **Reduced Motion**: Respects browser preferences (`prefers-reduced-motion: reduce`) by disabling logo parallax effects and menu transitions. |
| 226 | +- **Semantic Landmarks**: Uses standard HTML5 landmarks (`<nav>`, `<section>`, `<aside>`) with explicit labels. |
| 227 | + |
| 228 | +### Security |
| 229 | + |
| 230 | +- **URL Whitelisting**: All navigation links are validated against an allowed protocol list (`http:`, `https:`, `mailto:`). Unsafe links (such as `javascript:` execution strings) are discarded. |
| 231 | +- **PII Protection**: Telemetry payloads send item IDs and link labels only; no user details or page context values are collected. |
| 232 | +- **HTML Sanitization**: Custom footer templates are sanitized using `DOMPurify` to prevent cross-site scripting (XSS) vectors. |
| 233 | + |
| 234 | +<img src="https://m365-visitor-stats.azurewebsites.net/sp-dev-fx-extensions/samples/react-application-navigation-header" /> |
0 commit comments