UNPKG

@stihl-design-system/components

Version:

Welcome to the STIHL Design System react component library.

112 lines (111 loc) 6.02 kB
export declare const ARIA_LIVE_REGION_ALERT_ID = "ds-alert-live-region"; export declare const ARIA_LIVE_REGION_STATUS_ID = "ds-status-live-region"; export declare const getAriaAlertLiveRegionElement: () => HTMLElement | null | undefined; export declare const getAriaStatusLiveRegionElement: () => HTMLElement | null | undefined; export declare const validateMultipleDSAriaLiveRegionsOnPage: () => void; /** * Ensures the two DS live regions exist exactly once on the page, directly under <body>. * - If both exist: no-op. * - If none exist: injects them under document.body. * - If only one exists: throws (broken page state). * - If duplicates exist: throws (existing validation). * * ## Background: Micro-Frontend / AEM Web Component Support * * This function was introduced to support complex hosting environments where React components * are compiled into Web Components and embedded via systems like AEM (Adobe Experience Manager). * * In these setups: * - React components become self-contained widgets, not full SPAs * - Multiple independent micro-frontends may exist on a single page * - Each micro-frontend has its own encapsulated React/VDOM render process * - Web Components render sequentially based on DOM registration order * - Shadow DOM is typically disabled, so elements are detectable across components * * ### The Problem * * The standard `<DSAriaLiveRegions />` placement guideline ("as close to `<body>` as possible") * is impossible to follow when components can only be placed at the root of each Web Component * wrapper, not the actual document body. This creates two failure modes: * * 1. **Missing live regions**: If no static HTML snippet exists and the component isn't rendered, * dependent components (DSChipGroup, DSToast, etc.) throw errors. * 2. **Duplicate live regions**: Multiple Web Components each rendering their own live regions * creates invalid HTML (duplicate IDs) and unpredictable screen reader behavior. * * ### Why Placement Matters for Accessibility * * A mode that allows `DSAriaLiveRegions` to render inside arbitrary micro-frontend wrappers * is risky for accessibility. Those wrappers can later become `aria-hidden`, `inert`, `hidden`, * or be moved under a `<dialog>`, and at that point announcements can become intermittent or * stop entirely across screen readers. This is exactly why the requirement to place live regions * as close to `<body>` as possible exists. * * Additionally, treating duplicates as "warn and keep going" is not harmless. As soon as * duplicate IDs exist, `getElementById()` effectively selects one instance based on document * order. If that instance lives in a subtree that later becomes hidden, announcements will * silently break even though "a live region exists somewhere" on the page. * * ### The Solution: `microFrontendMode` * * Instead of rendering where mounted (which could be inside problematic wrappers), this mode: * * 1. **Renders nothing locally** - The component returns `null` * 2. **Injects directly under `document.body`** - Guarantees correct placement regardless of * where the component is used in the React tree * 3. **Is idempotent** - Whichever MFE instance runs first installs the body-level regions, * all subsequent calls no-op safely * 4. **Maintains strict validation** - True duplicates remain a hard error * * This provides rollout safety for MFEs and templates without compromising accessibility * correctness. The exact render order doesn't matter as long as the logic is idempotent * and synchronous. * * ### Recommended Integration Pattern * * 1. **Ideal**: Add static HTML live regions to the root `index.html` or AEM page template * 2. **Fallback**: Use `<DSAriaLiveRegions microFrontendMode />` at the root of each * micro-frontend as a self-healing fallback * * With this pattern: * - If static HTML exists, all `microFrontendMode` instances no-op * - If no static HTML exists, the first MFE to render installs the regions * - Subsequent MFEs detect the existing regions and no-op * - No duplicates, no missing regions, no placement issues */ export declare const ensureAriaLiveRegions: (srOnlyClassName: string) => void; /** * Gets the alert live region element if present on the page and returns it. * Throws an error with the component name if the element is not found. * * @param componentName - The component name for error messages if live region is missing * @returns The alert live region HTMLElement * @throws Error if the alert live region element is not found */ export declare const getAlertLiveRegionOrThrow: (componentName: string) => HTMLElement; /** * Gets the status live region element if present on the page and returns it. * Throws an error with the component name if the element is not found. * * @param componentName - The component name for error messages if live region is missing * @returns The status live region HTMLElement * @throws Error if the status live region element is not found */ export declare const getStatusLiveRegionOrThrow: (componentName: string) => HTMLElement; /** * Sets a message to the alert live region (role="alert", aria-live="assertive"). * Use for urgent announcements that should interrupt the user (e.g., warnings, errors). * * @param message - The message to announce * @param componentName - The component name for error messages if live region is missing */ export declare const setAriaAlertMessage: (message: string, componentName: string) => void; /** * Sets a message to the status live region (role="status", aria-live="polite"). * Use for non-urgent announcements that should wait for user pause (e.g., status updates, success messages). * The message is automatically cleared after a short delay. * * @param message - The message to announce * @param componentName - The component name for error messages if live region is missing */ export declare const setAriaStatusMessage: (message: string, componentName: string) => void;