ngx-accessible-ui v1.0.14
Accessible Navigation & Menu Directives for Angular
Overview
Two powerful Angular directives to create or transform any website into a fully accessible experience with keyboard
, touch
, and mouse support with ease:
accessibleNavigation
– Enables seamless keyboard navigation across all sections of a webpage.accessibleMenu
– Transforms any menu into a fully accessible, keyboard-navigable menu.
Both directives comply with WCAG 2.1 Level AA and the European Accessibility Act 2025, ensuring a highly inclusive web experience.
Installation
To install the directives in your Angular project, use:
npm i ngx-accessible-ui
or
yarn add ngx-accessible-ui
Usage
Import the directives into your Angular module:
import { NgxAccessibleUiModule } from 'ngx-accessible-ui';
@NgModule({
imports: [NgxAccessibleUiModule],
})
export class AppModule {}
Now, you can use them in your HTML as described below.
Learn with:
accessibleMenu Basic Live Demo For Angular 19
accessibleNavigation Basic Live Demo For Angular 19
accessibleMenu Advance Live Demo For Angular 19
accessibleMenu Advance Numpad Live Demo For Angular 19
accessibleNavigation
Directive
<div id="header" accessibleNavigation [navMap]="{ page: 1, section: 1 }">
<button data-item="navigationitem">Item 1</button>
<button data-item="navigationitem">Item 2</button>
</div>
<div id="main" accessibleNavigation [navMap]="{ page: 1, section: 2 }">
<button data-item="navigationitem">Item 1</button>
<button data-item="navigationitem">Item 2</button>
</div>
accessibleNavigation Basic Live Demo For Angular 19
For detailed documentation, refer to Full Documentation.
accessibleMenu
Directive
<button accessibleMenu [mainMenu]="true">Open Main Menu</button>
<ul>
<li role="menuitem">Item 1</li>
<button role="menuitem" accessibleMenu>Item 2 Submenu Level 1</button>
<ul>
<li role="menuitem">Sub-item Level 1.1</li>
<li role="menuitem">Sub-item Level 1.2</li>
</ul>
</ul>
accessibleMenu Basic Live Demo For Angular 19
accessibleMenu Advance Live Demo For Angular 19
accessibleMenu Advance Numpad Live Demo For Angular 19
For detailed documentation, refer to Full Documentation.
Full Documentation
1 Angular Directive accessibleNavigation
2 Angular Directive accessibleMenu
Angular Directive accessibleNavigation
The accessibleNavigation
directive, combined with the accessibleMenu
directive, enables seamless navigation using all input methods and all directional navigation in any Angular website adhering to WCAG 2.1 Level AA standards and the European Accessibility Act 2025. The directive provides advanced keyboard navigation and focus management between different sections of pages to enhance accessibility in web applications. It dynamically manages focusable elements within a container or section and integrates modern web APIs like IntersectionObserver
and MutationObserver
to adapt to DOM element changes and element visibility.
Key Features
Advanced Keyboard Navigation & Focus Management
- Default navigation: Tab, Shift+Tab for sections like header, footer, main, aside, etc.; Arrow keys for elements in sections.
- Supports all directional navigation, irrespective of grid, table, float, or any other structure.
- Automatically manages focus between navigable pages (i.e., components or child components) when they open or close and remembers the last navigated section on every page and sets focus to the last active element in that section.
Dynamic Navigation Map
- Maintains a static navigation map that tracks page and section information.
- Automatically updates the navigation map as items are added, removed, or modified.
Observer Integration for Responsive Updates
- Utilizes IntersectionObserver to detect when a page becomes visible and adjust focus accordingly.
- Employs MutationObserver to watch for DOM changes (child list) to refresh navigation items dynamically (supports
*ngIf
/*ngFor
). Also, includes a fallback for browsers that do not supportIntersectionObserver
andMutationObserver
.
Customizable Navigation Inputs
- Offers several
@Input()
properties (e.g.,sectionNavKey
,navUp
,navDown
,navLeft
,navRight
,navKeys
) for tailoring navigation behavior. - Supports setting a default focus item of a section via the
defaultNavItemId
input. - If space and enter do not work on a button or anchor tag, use
[navOpenKeys]="[' ', 'Enter']"
to enable click behavior on space and enter keypress. The default is['']
.
Lock Focus and Scrollable Container Support
- Allows focus to lock on popups or modal-like components and child components (i.e., pages).
- Allows specifying a scrollable container (using
scrollableContainerId
) to handle scrolling with keys such asPageUp
,PageDown
,Home
, andEnd
in scrollable components or pages while maintaining locked focus and navigation.
Accessibility Compliance
- Ensures that navigation items are focusable by automatically assigning
tabindex
where needed. - Designed to work seamlessly with assistive technologies by managing focus order and element visibility.
Lifecycle Handling
- Automatically cleans up observers on directive destruction.
- Handles edge cases for hidden/removed elements.
Requirements
To ensure the directive works as intended, follow these key rules:
1. Apply the accessibleNavigation
directive to each container element (header, main, footer, etc.) that wraps all navigable items on a page.
2. Provide page and section numbers using [navMap]="{ page: 1, section: 1 }"
(section 1
for header, 2
for main, 3
for footer, etc.; page 2
for "About Us," 3
for "Contact Us," etc.). Ensure page and section numbers start from 1
.
3. Assign the attribute data-item="navigationitem"
to all child elements intended for navigation, regardless of their position within the container or section.
Basic Structure
<div id="header" accessibleNavigation [navMap]="{ page: 1, section: 1 }">
<button data-item="navigationitem">Item 1</button>
<button data-item="navigationitem">Item 2</button>
</div>
<div id="main" accessibleNavigation [navMap]="{ page: 1, section: 2 }">
<button data-item="navigationitem">Item 1</button>
<button data-item="navigationitem">Item 2</button>
</div>
Optional Features
Default Navigation Element
Specify the ID of the element to be focused by default. If not specified or unavailable, focus will automatically shift to the first visible element in the viewport. Automatically detects changes to the default navigation item when the bound variable specifying its ID updates and shifts focus accordingly when navigating to that section.
<div accessibleNavigation [defaultNavItemId]="'linkNameId' + numberVariable">
<button id="link1" data-item="navigationitem">Item 1</button>
<button id="link2" data-item="navigationitem">Item 2</button>
</div>
Custom Navigation Keys
Override default navigation key arrays:
<div accessibleNavigation
[navUp]="['W', 'ArrowUp']"
[navDown]="['S', 'ArrowDown']"
[navLeft]="['A', 'ArrowLeft']"
[navRight]="['D', 'ArrowRight']">
<!-- Navigation items -->
</div>
Scrollable Container
If your container is scrollable but is a popup or modal-like page, and scrolling is happening in the background instead of the current page, set the container ID to enable proper handling of scrolling keys: PageUp
, PageDown
, Home
, and End
to scroll only the current page scrollable container.
<div id="scrollableContainer" style="height: 400px; overflow-y: auto;">
<div accessibleNavigation [scrollableContainerId]="'scrollableContainer'">
<!-- Navigation items -->
</div>
</div>
Subtree Option
Watches for changes in the descendants
of direct child elements within the container (default: true
). Set [subtree]="false"
if change in direct child elements is enough for mutation observer to refresh navigation items and there are many items in that section.
Ignoring Keypress in Inputs
By default, keypress events are ignored in ['text', 'search', 'range']
input types. Additional input types can be specified:
[inputTypesToIgnoreOnKeypress]="['text', 'search', 'range', 'additionalInputType']"
Always Refresh Navigation Items
Enable [alwaysRefreshNavItems]="true"
to update navigation items dynamically on every keypress if items are few but keep changing.
Lock Focus
Set [lockFocus]="true"
to lock focus within a popup or modal-like page, if focus or scrolling is happening in the background instead of the current page, by applying event.preventDefault()
on each keypress as long as focus is inside that page. Limit scrolling with PageUp, PageDown, Home, and End keys to the specified scrollable container if an ID is specified with [scrollableContainerId] = "'scrollableContainerId'"
.
NavKeysToExitInputElement
Configure keys to exit an input element (default: ['Tab', 'Escape', 'ArrowDown', 'ArrowUp']
).
NavOpenKeys
Define keys to open a navigation item with click (default: ['']
). Use [navOpenKeys]="[' ', 'Enter']"
when space or enter does not trigger a click event.
Other Configuration Options
Input | Default Values | Description |
---|---|---|
navMap | { page: null, section: null } | Page and section number for navigation map |
sectionNavKey | ['Tab'] | Keys for section navigation |
Notes
- Uses Angular lifecycle hooks (
AfterViewInit
,OnDestroy
) to manage observers. - Available as
accessibleNavigation
viaexportAs
for dynamic focus handling.
Angular Directive accessibleMenu
Overview
The accessibleMenu
directive is designed to create or convert any existing menu into fully accessible menus and submenus that comply with WCAG 2.1 Level AA and the European Accessibility Act 2025. It ensures seamless navigation via keyboard, mouse, and touch while providing advanced features like dynamic ARIA attributes, multi-level menu support, and customizable search functionality.
Key Features
1. Accessibility Compliance
- WCAG 2.1 Level AA & European Accessibility Act 2025 Compliant: Ensures menus are fully accessible via keyboard and meet modern accessibility standards.
- Dynamic ARIA Attributes: Automatically assigns
aria-haspopup
,role
,aria-controls
, andaria-expanded
attributes for proper screen reader support. - Assistive Technology Compatibility: Works seamlessly with screen readers and other assistive technologies.
2. Navigation
- Keyboard, Mouse, and Touch Support: Enables navigation using all input methods.
- Restricted Focus for Keyboard Users: Keeps focus within the current menu or submenu until the Escape key (for main menu) or Left Arrow/Escape key (for submenu) is pressed.
- All-Direction Navigation: Allows navigation in all directions using arrow keys, regardless of menu structure (grid, table, float, etc.).
- Numpad Support for Touch Users: Enables touch users to navigate or input using a numpad without activating the native keyboard.
3. Dynamic Menu Behavior
- Multi-Level Menu Support: Handles infinite levels of nested menus.
- Auto Close: Closes other menus when a new menu is opened or when clicking outside the menu.
- Dynamic Open/Close Control: Supports submenus and items that remain always open or dynamically open based on data attributes.
4. Search Functionality
- Advanced Two-Level Search: Allows menu-wise and item-wise search using a single input field.
- Numpad Search: Enables search using numpad keys (touch, mouse, or number keys).
- Direct Search: If no search field or numpad is present, direct search is performed using any key.
5. Customization
- Custom Navigation Keys: Override default navigation keys per menu using
(navUp)
,(navDown)
,(navOpenMenu)
,(navExitMenu)
,(navLeft)
, and(navRight)
. - Template Variables: Use template variables for conditional rendering (e.g., showing different icons based on menu state).
- Shortcut Keys: Open the main menu using a specific key combination (e.g.,
Ctrl+Alt+X
).
Requirements
To ensure the directive works as intended, follow these rules:
- Apply the
accessibleMenu
directive to the menu-opening element (e.g.,<button>
,<div>
). - Use the
mainMenu
input to designate the main menu button:<button accessibleMenu [mainMenu]="true">Open Main Menu</button>
- The menu container must be the next sibling (
nextElementSibling
) of the menu-opening element. - Assign
role="menuitem"
to all menu items, regardless of their position in the menu container.
Basic Structure
<button accessibleMenu [mainMenu]="true">Open Main Menu</button>
<ul>
<li role="menuitem">Item 1</li>
<button role="menuitem" accessibleMenu>Item 2 Submenu Level 1</button>
<ul>
<li role="menuitem">Sub-item Level 1.1</li>
<li role="menuitem">Sub-item Level 1.2</li>
</ul>
</ul>
Optional Features
1. All-Direction Navigation
Enable navigation in all directions using arrow keys:
<button accessibleMenu [allDirectionNavigation]="true">Open Menu</button>
2. Advanced Two-Level Search
Enable search functionality using an input field: Menu-wise and item-wise search using the same input field. Example: Searching "Italian" shows all items under the "Italian" menu and any matching items like "Italian Dressing" or "Italian Soda" across other menus.
<input type="text" role="menuitem" data-use-search="true" placeholder="Search...">
3. Keep Submenu Open
Keep a submenu open using the data-keep-submenu-open
attribute:
<button role="menuitem" accessibleMenu data-keep-submenu-open="true">Open Submenu</button>
4. Always Open Submenu Item
- Simple Example:
<li role="menuitem" data-always-open="true">Sub-item Level 2.2</li>
- Conditional Example:
<li role="menuitem" [attr.data-always-open]="(author === 'Default') ? 'true' : 'false'">
Sub-item Level 2.2
</li>
5. Remember Last Menu Item
<button accessibleMenu [rememberLastMenuitem]="true">Open Menu</button>
6. Close Menu Upon Selection
<button accessibleMenu [closeMenuUponSelection]="true">Open Menu</button>
7. Custom Navigation Keys
<button accessibleMenu (navUp)="['ArrowUp', 'W']" (navDown)="['ArrowDown', 'S']">Open Menu</button>
8. Template Variables
<button accessibleMenu #templateVar="accessibleMenu">
<svg *ngIf="templateVar.menuState === 'Close'">Left Arrow Icon</svg>
<svg *ngIf="templateVar.menuState === 'Open'">Down Arrow Icon</svg>
</button>
9. Numpad Support
<button accessibleMenu [mainMenu]="true">Open Main Menu</button>
<ul>
<li role="menuitem">Item 1</li>
<li role="menuitem">Item 2</li>
<aside role="menuitem" data-use-numpad="true">
<div role="status">Enter Number</div>
<div class="numpad">
<button *ngFor="let button of ['1','2','3','4','5','6','7','8','9']" role="button" data-button-type="number">{{ button }}</button>
<button role="button" data-button-type="backspace">⌫</button>
<button role="button" data-button-type="number">0</button>
<button role="button" data-button-type="enter">↵</button>
</div>
</aside>
</ul>
10. Shortcut Key
<button accessibleMenu [shortcutKey]="'M'">Open Main Menu</button>
Configuration Options
Input | Default Values | Description |
---|---|---|
inputTypesToIgnoreOnKeypress | ['text', 'search', 'range'] | Input types to ignore keypress events |
navKeysToExitInputElement | ['Tab', 'Escape', 'ArrowDown', 'ArrowUp'] | Keys to exit an input element |
navUp | ['ArrowUp'] | Keys for navigating up |
navDown | ['ArrowDown', 'Tab'] | Keys for navigating down |
navLeft | ['ArrowLeft'] | Keys for navigating left |
navRight | ['ArrowRight'] | Keys for navigating right |
navOpenMenu | [' ', 'Enter'] | Keys for opening a menu |
navExitMenu | ['Escape'] | Keys for closing a menu |
Notes
- Fully supports Angular's
*ngIf
for dynamic rendering. - Works seamlessly with custom templates and dynamic DOM changes.
- Available as
accessibleMenu
viaexportAs
for dynamic focus handling.
Contributing
We welcome contributions! If you find an issue or want to improve this package:
- Fork the repository
- Create a new branch (
feature/my-feature
) - Commit your changes
- Open a pull request
License
This project is licensed under the MIT License.
Maintained by: Shakeel Kadri