Skip to content

Tooltip/Popover: dismiss on Escape key (WCAG 1.4.13) #268

Description

@mrholek

Summary

Hover/focus-triggered tooltips and popovers cannot be dismissed with the keyboard. Per WCAG 1.4.13 "Content on Hover or Focus", content shown on hover/focus must be dismissible without moving the pointer or focus — pressing Escape should hide it.

This is already shipped in the other editions; this issue tracks the Angular port for parity:

Scope

Both TooltipDirective and PopoverDirective (projects/coreui-angular/src/lib/{tooltip,popover}/*.directive.ts), free and pro.

Suggested approach

Both directives already drive visibility through the visible model signal. Mirror the pattern used in the other editions (React useEffect([_visible]), Vue watch(visible)): react to visible() and toggle a document-level keydown listener registered in the capture phase.

readonly #escapeEffect = effect((onCleanup) => {
  if (!this.visible()) {
    return;
  }

  const handleKeyDown = (event: KeyboardEvent) => {
    if (event.key !== 'Escape') {
      return;
    }
    event.preventDefault();
    event.stopPropagation();
    this.visible.set(false);
  };

  this.#document.addEventListener('keydown', handleKeyDown, true);
  onCleanup(() => this.#document.removeEventListener('keydown', handleKeyDown, true));
});

Notes:

  • Capture phase (true) is required — it lets a tooltip/popover shown inside a dialog dismiss before the dialog's own Escape handler (nested dismissal: first Escape closes the tooltip, the next closes the dialog).
  • #document is already injected (inject(DOCUMENT)); effect's onCleanup handles both visibility flips and teardown, so no separate ngOnDestroy wiring is needed. (An afterRenderEffect/plain listener via Renderer2.listen is an option too, but Renderer2.listen can't request the capture phase — use addEventListener directly.)

Tests

Add karma specs to both directives: (1) a shown tooltip/popover is hidden when Escape is dispatched on document; (2) a non-Escape key leaves it visible.

Docs

Add the same note the other editions use, under the tooltip/popover Usage section:

A shown tooltip can be dismissed by pressing the Escape key, helping satisfy the WCAG 1.4.13 "Content on Hover or Focus" success criterion.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions