AccessibilityKit
AppA11y helpers bundle that exposes the SkipLink, LiveRegion (Announcer) and Tooltip primitives through a single partial. The `part` prop (skip|live|announcer|tooltip|all) picks which piece to render; the default usage mounts the SkipLink + LiveRegion at the top of the page and exposes the `window.announce` API.
Page head (Tab to reveal SkipLink)
Skip to main content<div role="status" aria-live="polite" class="sr-only"></div>
LiveRegion mounts hidden; window.announce('Saved!') updates it.
<%- include('modules/app/AccessibilityKit') %>
<%# Anywhere in the page %>
…
<%- include('modules/app/AccessibilityKit', {
part: 'tooltip',
content: 'Helpful hint',
placement: 'top',
children: `<%- include('modules/ui/Button', { variant: 'outline', size: 'sm', children: 'Hover me' }) %>`
}) %>
<%
// AccessibilityKit re-exports SkipLink, LiveRegion, Announcer, and Tooltip
// from the underlying ui/ primitives. This EJS file renders any of them
// based on `locals.part` ('skip' | 'live' | 'announcer' | 'tooltip'),
// and by default renders SkipLink + LiveRegion (matching the typical
// top-of-document usage) and exposes window.announce for ad-hoc updates.
var _part = locals.part || 'all';
var _skipHref = locals.skipHref || locals.href || '#main-content';
var _skipLabel = locals.skipLabel || locals.label || 'Skip to main content';
var _politeness = locals.politeness || 'polite';
var _message = locals.message || '';
var _liveId = locals.liveId || 'a11y-live-region';
var _className = locals.className || '';
// Tooltip locals
var _tipContent = locals.content || '';
var _tipPlacement = locals.placement || 'top';
var _tipTheme = locals.theme || 'default';
var _tipArrow = !!locals.arrow;
var _tipDelay = Number(locals.delay || 0);
var _tipId = locals.tooltipId || ('tooltip-' + Math.random().toString(36).slice(2, 8));
var _themeMap = {
'default': 'bg-surface-overlay text-text-primary border border-border',
'dark': 'bg-gray-900 text-white border-transparent',
'light': 'bg-white text-gray-900 border border-border shadow-md'
};
var _placementMap = {
'top': 'bottom-full left-1/2 -translate-x-1/2 mb-2',
'bottom': 'top-full left-1/2 -translate-x-1/2 mt-2',
'left': 'right-full top-1/2 -translate-y-1/2 mr-2',
'right': 'left-full top-1/2 -translate-y-1/2 ml-2'
};
var _arrowPlacement = {
'top': 'bottom-[-5px] left-1/2 -translate-x-1/2 border-t-0 border-l-0',
'bottom': 'top-[-5px] left-1/2 -translate-x-1/2 border-b-0 border-r-0',
'left': 'right-[-5px] top-1/2 -translate-y-1/2 border-l-0 border-b-0',
'right': 'left-[-5px] top-1/2 -translate-y-1/2 border-r-0 border-t-0'
};
var _arrowTheme = {
'default': 'bg-surface-overlay',
'dark': 'bg-gray-900 border-transparent',
'light': 'bg-white'
};
var _tipThemeCls = _themeMap[_tipTheme] || _themeMap['default'];
var _tipPlacementCls = _placementMap[_tipPlacement] || _placementMap['top'];
var _tipArrowPlace = _arrowPlacement[_tipPlacement] || _arrowPlacement['top'];
var _tipArrowTheme = _arrowTheme[_tipTheme] || _arrowTheme['default'];
%>
<% if (_part === 'all' || _part === 'skip') { %>
<%= _skipLabel %>
<% } %>
<% if (_part === 'all' || _part === 'live' || _part === 'announcer') { %>
<%= _message %>
<% } %>
<% if (_part === 'tooltip') { %>
<%- locals.children || '' %>
<%- _tipContent %>
<% if (_tipArrow) { %>
<% } %>
<% } %>