core/common/dropdown-focus-trap.directive.ts

Description

Directive to manage focus trapping and keyboard navigation for ngx-bootstrap dropdowns with container="body".

Problem

When a dropdown is appended to the body using container="body", the standard cdkTrapFocus directive doesn't work because the dropdown content is outside the normal DOM hierarchy where the directive is applied.

Solution

This directive:

  • Detects when a dropdown with container="body" opens
  • Programmatically creates a CDK focus trap on the body-appended dropdown menu element
  • Traps Tab/Shift+Tab navigation within the dropdown menu
  • Automatically closes dropdown and restores focus to toggle button when user selects an item with Enter/Space
  • Prevents ESC key from propagating to parent elements (e.g., modals, drawers) and restores focus on close
  • Cleans up all listeners when the dropdown closes

Usage

Simply apply this directive to the same element that has the dropdown directive:

Example :
<div dropdown container="body" c8yDropdownFocusTrap #myDropdown="bs-dropdown">
  <button dropdownToggle>Select option</button>
  <div *dropdownMenu class="dropdown-menu">
    <c8y-list-group role="list">
      <c8y-li tabindex="0" role="listitem">Option 1</c8y-li>
      <c8y-li tabindex="0" role="listitem">Option 2</c8y-li>
    </c8y-list-group>
  </div>
</div>

Features

  • Focus trapping: Tab key navigation cycles through dropdown items
  • Automatic focus management: Enter/Space automatically closes dropdown and returns focus to toggle button
  • ESC key isolation: Pressing ESC closes only the dropdown, not parent modals/drawers, and restores focus
  • Form-friendly: Skips automatic close for inputs, textareas, and selects within the dropdown
  • Automatic cleanup: All listeners and focus trap removed when dropdown closes
  • Zero configuration: Just add the directive, no manual focus management needed

See CDK FocusTrap

Implements

OnDestroy

Example

<b>Example :</b><div><pre class="line-numbers"><code class="language-html">&lt;div dropdown container=&quot;body&quot; c8yDropdownFocusTrap #myDropdown=&quot;bs-dropdown&quot;&gt;
  &lt;button dropdownToggle&gt;Select option&lt;/button&gt;
  &lt;div *dropdownMenu class=&quot;dropdown-menu&quot;&gt;
    &lt;c8y-list-group role=&quot;list&quot;&gt;
      &lt;c8y-li tabindex=&quot;0&quot; role=&quot;listitem&quot;&gt;Option 1&lt;/c8y-li&gt;
      &lt;c8y-li tabindex=&quot;0&quot; role=&quot;listitem&quot;&gt;Option 2&lt;/c8y-li&gt;
    &lt;/c8y-list-group&gt;
  &lt;/div&gt;
&lt;/div&gt;</code></pre></div><h2>Features</h2>
<ul>
<li><strong>Focus trapping</strong>: Tab key navigation cycles through dropdown items</li>
<li><strong>Automatic focus management</strong>: Enter/Space automatically closes dropdown and returns focus to toggle button</li>
<li><strong>ESC key isolation</strong>: Pressing ESC closes only the dropdown, not parent modals/drawers, and restores focus</li>
<li><strong>Form-friendly</strong>: Skips automatic close for inputs, textareas, and selects within the dropdown</li>
<li><strong>Automatic cleanup</strong>: All listeners and focus trap removed when dropdown closes</li>
<li><strong>Zero configuration</strong>: Just add the directive, no manual focus management needed</li>
</ul>

Metadata

Relationships

results matching ""

    No results matching ""