Getting StartedInstall and bootstrap headless foundations 4
LayoutHeadless structural primitives for expandable and container patterns 6
OverlayHeadless modal and floating layer behavior 3
FeedbackHeadless notification and status communication patterns 5
FormHeadless input and selection contracts 17
UtilityReusable action, identity, and clipboard behavior 6
NavigationHeadless trails, trees, menus, and command surfaces 7

API reference

Headless Menu is the panel primitive for dropdowns and nested submenus. Pair tngMenuTrigger with tngMenu for standalone triggers, or compose with tngMenubar when you need a horizontal command strip (see the Menubar docs).

tngMenu

Hosts role="menu", tracks open state, active item, typeahead, outside dismissal, and coordinates focus with an optional trigger or parent menubar.

Trigger + menu composition

html
<div class="menu-shell">
  <button type="button" [tngMenuTrigger]="apiCompositionFileMenu">File</button>
  <div tngMenu #apiCompositionFileMenu="tngMenu" aria-label="File menu">
    <button type="button" tngMenuItem tngMenuItemValue="new">New</button>
    <button type="button" tngMenuItem tngMenuItemValue="open">Open</button>
  </div>
</div>
InputTypeDetails
loopbooleanWraps vertical navigation at the ends of the item list. Defaults to true.
disabledbooleanPrevents opening the panel and clears interactive state.
closeOnSelectbooleanCloses the menu after a leaf selection. Defaults to true.
dismissOnOutsideClickbooleanCloses on pointer down outside. Defaults to true.
dismissOnFocusoutbooleanOptional focus-leave dismissal for custom focus traps. Defaults to false.
OutputstngMenuOpened, tngMenuClosed, tngMenuSelecttngMenuSelect carries value, itemId, and trigger ('keyboard' | 'pointer').
Hostrole, data-slot, data-state, hidden, aria-activedescendant Emits data-slot="menu", data-state="open" | "closed", and uses the native hidden attribute while closed. When a row is active, the panel also updates aria-activedescendant to the active item id.

tngMenuTrigger

Links a focusable host (commonly a button) to a tngMenu instance. The directive wires aria-controls, aria-expanded, and keyboard open/close behavior.

InputTypeDetails
[tngMenuTrigger]TngMenu | nullRequired reference to the menu instance (#ref="tngMenu").
data-slot'menu-trigger'Stable hook for styling the trigger surface.
Hostid, aria-haspopup, aria-controls, aria-expanded The trigger owns the accessible relationship to the linked panel and reflects open state through aria-expanded.
Disabled hostsnative / ARIA Honors disabled, disabled attribute, or aria-disabled="true".

tngMenuItem and structure helpers

Menu items participate in roving focus inside the panel. Use tngMenuGroupLabel and tngMenuSeparator for structure; submenu rows link nested tngMenu hosts with [tngMenuItemSubmenu]. Owned submenus can open by click or ArrowRight; leaf rows emit selection on click, Enter, or Space.

Nested submenu wiring

html
<div tngMenu #apiRootMenu="tngMenu" aria-label="Actions">
  <button type="button" tngMenuItem [tngMenuItemSubmenu]="apiImportMenu">Import…</button>

  <div tngMenu #apiImportMenu="tngMenu" aria-label="Import sources">
    <button type="button" tngMenuItem tngMenuItemValue="csv">CSV</button>
  </div>
</div>
DirectiveKey inputsNotes
tngMenuItemtngMenuItemValue, tngMenuItemRole, tngMenuItemChecked, tngMenuItemSubmenu Supports menuitem, menuitemcheckbox, and menuitemradio roles; checkbox/radio items surface aria-checked. Every item also exposes data-slot="menu-item"; active rows reflect data-active, and submenu owners reflect aria-haspopup, aria-controls, and aria-expanded.
tngMenuBackdrop[tngMenuBackdrop]Optional dismiss layer that closes the linked menu on click and exposes data-slot="menu-backdrop".
tngMenuGroupLabel, tngMenuSeparatorPresentation roles for labeled groups and dividers.

Structure and backdrop

Optional tngMenuBackdrop hosts forward clicks to close an open menu—useful for modal-like overlays or dimmed shells while keeping headless markup flexible.

Backdrop closes linked menu

html
<section class="menu-with-backdrop">
  <button type="button" [tngMenuTrigger]="apiBackdropPanel">Open</button>
  <div [tngMenuBackdrop]="apiBackdropPanel" class="menu-backdrop" aria-hidden="true"></div>
  <div tngMenu #apiBackdropPanel="tngMenu" aria-label="Actions">
    <button type="button" tngMenuItem tngMenuItemValue="save">Save</button>
  </div>
</section>

Events and focus token

Overlay-style hosts that reposition the panel after open can defer the initial focus move until coordinates are stable by providing the injection token below on the same element injector as tngMenu.

Defer initial focus until positioned

ts
import { TNG_MENU_DEFER_HOST_FOCUS_UNTIL_POSITIONED } from '@tailng-ui/primitives';

@Component({
  providers: [{ provide: TNG_MENU_DEFER_HOST_FOCUS_UNTIL_POSITIONED, useValue: true }],
  // ...
})
export class MenuWithDeferredFocusComponent {}

Keyboard contract

Standalone triggers use the keys below; when a menu is owned by tngMenubar, additional horizontal navigation is handled by the menubar primitive.

Keyboard baseline

text
Trigger (tngMenuTrigger)
  Enter / Space       Toggle open; focus stays on trigger when closed
  ArrowDown           Open and focus first enabled item
  ArrowUp             Open and focus last enabled item
  Escape              Close when open

Open menu panel
  ArrowDown / ArrowUp Move active item (respects loop)
  Home / End          Jump to first / last enabled item
  Typeahead           Matches visible item labels
  Enter / Space       Activate focused item (emits tngMenuSelect when applicable)
  Escape              Close; nested submenu closes before root

Submenus
  ArrowRight          Open owned submenu
  ArrowLeft           Close nested panel; focus returns to parent item