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

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