Skip to content

Commit 9d3314c

Browse files
authored
Merge pull request #1906 from NicolasKheirallah/react-application-navigation-header
Add React application navigation header samples
2 parents b6cf202 + c89151a commit 9d3314c

126 files changed

Lines changed: 44425 additions & 0 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
require('@rushstack/eslint-config/patch/modern-module-resolution');
2+
module.exports = {
3+
extends: ['@microsoft/eslint-config-spfx/lib/profiles/default'],
4+
parserOptions: { tsconfigRootDir: __dirname },
5+
plugins: ['react-hooks'],
6+
rules: {
7+
'@typescript-eslint/no-explicit-any': 'warn',
8+
'@typescript-eslint/no-unused-vars': ['error', { argsIgnorePattern: '^_' }],
9+
'react-hooks/rules-of-hooks': 'error',
10+
'react-hooks/exhaustive-deps': 'warn'
11+
},
12+
ignorePatterns: [
13+
'dist/',
14+
'lib/',
15+
'lib-commonjs/',
16+
'release/',
17+
'node_modules/',
18+
'temp/',
19+
'config/mocks/',
20+
'*.js.map',
21+
'*.d.ts.map'
22+
]
23+
};
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
# Auto detect text files and perform LF normalization
2+
* text=auto
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
name: CI
2+
3+
on:
4+
push:
5+
branches: [main]
6+
pull_request:
7+
branches: [main]
8+
9+
jobs:
10+
build:
11+
runs-on: ubuntu-latest
12+
steps:
13+
- uses: actions/checkout@v4
14+
15+
- name: Setup Node.js
16+
uses: actions/setup-node@v4
17+
with:
18+
node-version-file: '.nvmrc'
19+
cache: 'npm'
20+
21+
- name: Install dependencies
22+
run: npm ci
23+
24+
- name: Lint
25+
run: npm run lint
26+
27+
- name: Test
28+
run: npm run test
29+
30+
- name: Build
31+
run: npm run build
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
# Logs
2+
logs
3+
*.log
4+
npm-debug.log*
5+
6+
# Dependency directories
7+
node_modules
8+
9+
# Build generated files
10+
dist
11+
lib
12+
lib-dts
13+
lib-commonjs
14+
lib-esm
15+
jest-output
16+
release
17+
solution
18+
temp
19+
*.sppkg
20+
.heft
21+
22+
# Coverage directory used by tools like istanbul
23+
coverage
24+
25+
# OSX
26+
.DS_Store
27+
28+
# Visual Studio files
29+
.ntvs_analysis.dat
30+
.vs
31+
bin
32+
obj
33+
34+
# Resx Generated Code
35+
*.resx.ts
36+
37+
# Styles Generated Code
38+
*.scss.ts
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
legacy-peer-deps=true
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
22.14.0
Lines changed: 234 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,234 @@
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+
![SPFx 1.23.2](https://img.shields.io/badge/SPFx-1.23.2-green.svg)
19+
![Node.js v22](https://img.shields.io/badge/Node.js-v22-green.svg)
20+
![Toolchain: Heft](https://img.shields.io/badge/Toolchain-Heft-green.svg)
21+
![Compatible with SharePoint Online](https://img.shields.io/badge/SharePoint%20Online-Compatible-green.svg)
22+
![Does not work with SharePoint Server](https://img.shields.io/badge/SharePoint%20Server-Incompatible-red.svg)
23+
![Hosted Workbench Compatible](https://img.shields.io/badge/Hosted%20Workbench-Compatible-green.svg)
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+
![Navigation Items](./assets/NavItems.png)
87+
88+
**Mobile Navigation Drawer**
89+
![Mobile Navigation](./assets/MobileNav.png)
90+
![Mobile Navigation 2](./assets/MobileNav2.png)
91+
92+
**Fullscreen Panel**
93+
![Fullscreen Panel](./assets/FullscreenPanel.png)
94+
95+
### Admin Settings Panel
96+
97+
**Admin Panel - Overview & Configuration**
98+
![Admin Panel 1](./assets/AdminPanel1.png)
99+
![Admin Panel 2](./assets/AdminPanel2.png)
100+
![Admin Panel 3](./assets/AdminPanel3.png)
101+
102+
**Admin Panel - Styling & Colors**
103+
![Admin Panel 4](./assets/AdminPanel4.png)
104+
![Admin Panel 5](./assets/AdminPanel5.png)
105+
![Admin Panel 6](./assets/AdminPanel6.png)
106+
107+
### User Experience
108+
109+
**Settings Panel - User Profile**
110+
![Settings Panel User](./assets/SettingsPanelUser.png)
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" />
123 KB
Loading
126 KB
Loading
124 KB
Loading

0 commit comments

Comments
 (0)