# Dynamic Sign-In Menu Implementation Guide

## Overview

This guide demonstrates how to implement a dynamic, API-driven sign-in navigation menu in the Ontario Design System header. This is a **sample implementation** showing best practices for managing sign-in menu items dynamically.

**Note:** This is provided as a reference example for teams who want to build their own dynamic menu solution. The code is not part of the core Design System package.

## Features

✅ **API Integration** - Fetches menu items from your API endpoint
✅ **Accessibility** - Maintains ARIA roles and screen reader announcements

---

## Quick Start

This is a **sample implementation** you can adapt for your project. The code demonstrates patterns for:

-   Fetching menu data from an API
-   Dynamically generating accessible menu markup
-   Handling errors gracefully

### What the initialization actually does

When you call `initialize`, the script:

1. Finds the sign-in menu containers in the header (desktop and mobile lists).
2. Fetches sign-in items from your API (when `useApi: true`).
3. Builds menu markup (`<li><a>…</a></li>`) and inserts it into those lists.
4. If the API fails or returns no items, the menu stays empty unless you provide your own data.

---

## Running the demo locally

Opening the HTML file directly will break asset paths (fonts, logos, scripts). Run a local dev server instead.

```zsh
pnpm run dev
```

Then open:

```
http://localhost:3000/demos/sign-in-menu-dynamic/index.html
```

### 1. Review the Sample Code

See the demo at `/demos/sign-in-menu-dynamic/index.html` and reference implementation in `ontario-sign-in-menu-dynamic.js`.

### 2. Adapt for Your Project

Copy and modify the patterns to fit your specific requirements:

For the demo, the manager is the `OntarioSignInMenu` module defined in `ontario-sign-in-menu-dynamic.js`.
Call `initialize()` in a script that runs after the header markup exists (the demo loads the file with `defer`).

```javascript
// Example: Basic initialization
OntarioSignInMenu.initialize({
	useApi: true,
});
```

---

## API Integration

### Expected API Response Format

The actual API returns a simple structure with basic fields:

```json
{
	"items": [
		{
			"id": "service-ontario-account",
			"label": "ServiceOntario account",
			"description": "Health cards, driver's licences, licence plates",
			"url": "https://www.ontario.ca/page/serviceontario-account"
		},
		{
			"id": "ontario-business-account",
			"label": "ONBusiness",
			"description": "Business Registry, Licenses and Permits, Business Information",
			"url": "https://www.app.ics.gov.on.ca/onbis/"
		}
	]
}
```

### Required Fields

| Field   | Type   | Description                         |
| ------- | ------ | ----------------------------------- |
| `id`    | string | Unique identifier for the menu item |
| `label` | string | Display text for the menu item      |
| `url`   | string | Destination URL                     |

### Optional Fields

| Field         | Type   | Description               |
| ------------- | ------ | ------------------------- |
| `description` | string | Subtitle/description text |

### Example: Configuring Your API Endpoint

```javascript
const API_CONFIG = {
	endpoint: 'https://your-api.example.com/v1/sign-in-menu', // Your API endpoint
	timeout: 5000, // Request timeout in milliseconds
};
```

    		],
    	}),
    });
    // Re-initialize menu with fresh data

}

````

---

## Accessibility

The sample implementation demonstrates how to maintain accessibility features:

-   ✅ **ARIA Roles** - `role="menu"`, `role="menuitem"`, `role="none"`
-   ✅ **Descriptions** - `aria-describedby` links labels to descriptions
-   ✅ **Screen Reader Announcements** - Menu updates announced via `aria-live`
-   ✅ **Keyboard Navigation** - Compatible with existing ontario-header.js keyboard handling
-   ✅ **Focus Management** - Integrates with header focus trap

---

## Error Handling

### API Failure and Empty Results

If the API endpoint is not configured, the request fails, or the API returns zero items, the sign-in menu is hidden (treated as “no result”).

### Invalid Data

Menu items are validated before rendering. Invalid items are logged and skipped:

```javascript
// Logs warning and skips invalid items
console.warn('Invalid menu item skipped:', item);
````

### Timeout Protection

API requests timeout after 5 seconds (configurable):

```javascript
const API_CONFIG = {
	endpoint: '...',
	timeout: 5000, // Adjust as needed
};
```

---

## Migration from Static Menu

### Before (Static Handlebars)

```handlebars
{{> @header-sign-in-navigation-items labels=labels }}
```

### After (Dynamic Implementation)

1. Keep the container markup in your header template
2. Remove or comment out the static partial
3. Implement JavaScript to fetch and render menu items
4. Menu items are dynamically generated on page load

### Gradual Migration

You can run both systems during transition:

```javascript
// Example: Feature flag for gradual rollout
if (config.useDynamicMenu) {
	// Use dynamic implementation
	await initializeDynamicMenu();
} else {
	// Keep using static template
}
```

---

## Example: Backend API Endpoint

### Node.js/Express Example

```javascript
// Example: API endpoint for menu items
app.get('/api/v1/sign-in-menu', async (req, res) => {
	try {
		// Fetch from database or CMS
		const items = await db.query(`
			SELECT id, label, description, url
			FROM sign_in_menu_items
			WHERE is_active = true
			ORDER BY display_order ASC
		`);

		res.json({ items });
	} catch (error) {
		console.error('Error fetching sign-in links:', error);
		res.status(500).json({ error: 'Internal server error' });
	}
});
```

## Troubleshooting Your Implementation

### Menu Not Appearing

**Check:**

1. Container element exists in DOM
2. JavaScript loaded without errors
3. Console shows any error messages

### API Not Called

**Check:**

1. API endpoint URL is correct
2. CORS headers configured properly
3. Network tab shows the request
4. Authentication/credentials if required

## Browser Support

The sample implementation uses modern JavaScript:

-   ✅ Modern browsers (Chrome, Firefox, Safari, Edge)
-   ✅ IE11 (requires polyfills for `fetch`, `Promise`, `Array.from`)

### Example: IE11 Polyfills

```html
<script src="https://polyfill.io/v3/polyfill.min.js?features=fetch,Promise,Array.from"></script>
<script src="your-menu-implementation.js"></script>
```

---

## Performance Considerations

### Best Practices

-   **Caching** - Cache API responses to reduce server load
-   **Debouncing** - Avoid excessive re-renders
-   **Lazy Loading** - Consider lazy-loading for very long menus

### Example: Response Caching

```javascript
// Example: Client-side caching
const CACHE_DURATION = 5 * 60 * 1000; // 5 minutes
let cachedItems = null;
let cacheTime = 0;

async function fetchMenuItems() {
	const now = Date.now();

	if (cachedItems && now - cacheTime < CACHE_DURATION) {
		return cachedItems; // Return cached data
	}

	// Fetch fresh data from API
	const response = await fetch('/api/sign-in-menu');
	cachedItems = await response.json();
	cacheTime = now;

	return cachedItems;
}
```

---

## Additional Resources

-   **Demo**: See `/index.html` for interactive examples
-   **Sample Code**: Reference `ontario-sign-in-menu-dynamic.js` for implementation patterns
-   **Design System**: Visit the Ontario Design System documentation for header components

---

## Disclaimer

This is a **sample implementation** provided as a reference for development teams. It demonstrates best practices but should be adapted to fit your specific requirements, infrastructure, and security policies. The code is not part of the core Ontario Design System package and is not officially supported.

---

## Changelog

### Version 1.0.0 (January 2026)

-   Initial sample implementation
-   API integration patterns
-   Accessibility demonstrations
-   Error handling examples
