context-menu
Use a semantic trigger and content surface. AngularCSS owns right-click and keyboard disclosure, pointer placement, menu focus, and submenu navigation; AngularTS owns actions and checkbox or radio values.
<div ng-context-menu>
<div>Right click here</div>
<menu aria-label="Browser actions">
<button ng-click="reload()">Reload</button>
<button
aria-checked="{{ showBookmarks }}"
ng-click="showBookmarks=!showBookmarks"
>
Show Bookmarks Bar
</button>
</menu>
</div>
Ordinary click is left to the authored trigger. Right-click, Shift F10, and the Context Menu key open this component.
Basic And Submenu
Example
View source
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>AngularCSS Context Menu</title>
<link rel="stylesheet" href="../../css/preflight.css" />
<link rel="stylesheet" href="../../css/angular.css" />
<link rel="stylesheet" href="../example.css" />
<script src="../../js/angular-ts.umd.js"></script>
<script src="../../js/angular-css.umd.js"></script>
</head>
<body
ng-app="angular.css"
ng-cloak
ng-init="lastAction='None'"
data-example="context-menu-basic context-menu-demo context-menu-submenu"
>
<main class="visual-example">
<div id="context-menu-demo" ng-context-menu>
<div>Right click here</div>
<menu aria-label="Browser actions">
<section>
<button ng-click="lastAction='Back'">
Back
<kbd>Alt+Left</kbd>
</button>
<button disabled>
Forward
<kbd>Alt+Right</kbd>
</button>
<button ng-click="lastAction='Reload'">
Reload
<kbd>Ctrl+R</kbd>
</button>
</section>
<hr />
<section>
<button ng-click="lastAction='Save'">
Save
<kbd>Ctrl+S</kbd>
</button>
</section>
<details>
<summary>More Tools</summary>
<menu>
<section>
<button ng-click="lastAction='Save Page'">Save Page...</button>
<button ng-click="lastAction='Create Shortcut'">
Create Shortcut...
</button>
<button ng-click="lastAction='Name Window'">
Name Window...
</button>
</section>
<hr />
<button ng-click="lastAction='Developer Tools'">
Developer Tools
</button>
</menu>
</details>
<hr />
<button variant="destructive" ng-click="lastAction='Delete'">
Delete
</button>
</menu>
</div>
<output class="context-menu-output" aria-live="polite">
Last action: <span ng-bind="lastAction"></span>
</output>
</main>
</body>
</html>
Content And State
Icons, destructive actions, groups, shortcuts, checkbox values, and radio values are functional packaged scenarios.
View source
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>AngularCSS Context Menu Workflows</title>
<link rel="stylesheet" href="../../css/preflight.css" />
<link rel="stylesheet" href="../../css/angular.css" />
<link rel="stylesheet" href="../example.css" />
<script src="../../js/angular-ts.umd.js"></script>
<script src="../../js/angular-css.umd.js"></script>
</head>
<body
ng-app="angular.css"
ng-cloak
ng-init="action='None'; view={bookmarks:true,urls:false}; person='pedro'; theme='light'"
data-example="context-menu-checkboxes context-menu-destructive context-menu-groups context-menu-icons context-menu-radio context-menu-shortcuts"
>
<main class="context-menu-workflow-grid visual-example">
<section class="context-menu-workflow" aria-labelledby="icons-title">
<h2 id="icons-title">Icons and destructive action</h2>
<div ng-context-menu>
<div>Right click here</div>
<menu aria-label="Editing actions">
<section>
<button ng-click="action='Copy'">
<svg
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
aria-hidden="true"
>
<rect x="9" y="9" width="11" height="11" rx="2"></rect>
<path
d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"
></path>
</svg>
Copy
</button>
<button ng-click="action='Cut'">
<svg
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
aria-hidden="true"
>
<circle cx="6" cy="6" r="3"></circle>
<circle cx="6" cy="18" r="3"></circle>
<path d="m20 4-8.5 8.5"></path>
<path d="m14.5 14.5 5.5 5.5"></path>
</svg>
Cut
</button>
<button ng-click="action='Paste'">
<svg
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
aria-hidden="true"
>
<rect x="5" y="4" width="14" height="18" rx="2"></rect>
<path d="M9 4.5V2h6v2.5"></path>
</svg>
Paste
</button>
</section>
<hr />
<button variant="destructive" ng-click="action='Delete'">
<svg
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
aria-hidden="true"
>
<path d="M3 6h18"></path>
<path d="M8 6V4h8v2"></path>
<path d="m19 6-1 15H6L5 6"></path>
</svg>
Delete
</button>
</menu>
</div>
<output>Action: <span ng-bind="action"></span></output>
</section>
<section class="context-menu-workflow" aria-labelledby="groups-title">
<h2 id="groups-title">Groups and shortcuts</h2>
<div ng-context-menu>
<div>Right click here</div>
<menu aria-label="File actions">
<section>
<h3>File</h3>
<button>New File <kbd>Ctrl+N</kbd></button>
<button>Open File <kbd>Ctrl+O</kbd></button>
<button>Save <kbd>Ctrl+S</kbd></button>
</section>
<hr />
<section>
<h3>Edit</h3>
<button>Undo <kbd>Ctrl+Z</kbd></button>
<button disabled>Redo <kbd>Shift+Ctrl+Z</kbd></button>
</section>
</menu>
</div>
</section>
<section class="context-menu-workflow" aria-labelledby="checkbox-title">
<h2 id="checkbox-title">Checkboxes</h2>
<div ng-context-menu>
<div>Right click here</div>
<menu aria-label="View options">
<button
aria-checked="{{ view.bookmarks }}"
ng-click="view.bookmarks=!view.bookmarks"
>
Show Bookmarks Bar
</button>
<button
aria-checked="{{ view.urls }}"
ng-click="view.urls=!view.urls"
>
Show Full URLs
</button>
</menu>
</div>
<output>
Bookmarks: <span ng-bind="view.bookmarks ? 'On' : 'Off'"></span>
</output>
</section>
<section class="context-menu-workflow" aria-labelledby="radio-title">
<h2 id="radio-title">Radio groups</h2>
<div ng-context-menu>
<div>Right click here</div>
<menu aria-label="Profile and theme">
<section>
<h3>People</h3>
<fieldset aria-label="People">
<button
aria-checked="{{ person === 'pedro' }}"
ng-click="person='pedro'"
>
Pedro Duarte
</button>
<button
aria-checked="{{ person === 'colm' }}"
ng-click="person='colm'"
>
Colm Tuite
</button>
</fieldset>
</section>
<hr />
<section>
<h3>Theme</h3>
<fieldset aria-label="Theme">
<button
aria-checked="{{ theme === 'light' }}"
ng-click="theme='light'"
>
Light
</button>
<button
aria-checked="{{ theme === 'dark' }}"
ng-click="theme='dark'"
>
Dark
</button>
<button
aria-checked="{{ theme === 'system' }}"
ng-click="theme='system'"
>
System
</button>
</fieldset>
</section>
</menu>
</div>
<output>
Person: <span ng-bind="person"></span>; Theme:
<span ng-bind="theme"></span>
</output>
</section>
</main>
</body>
</html>
Placement
The six physical and logical side options anchor to the invocation point and remain constrained to the viewport.
View source
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>AngularCSS Context Menu Sides</title>
<link rel="stylesheet" href="../../css/preflight.css" />
<link rel="stylesheet" href="../../css/angular.css" />
<link rel="stylesheet" href="../example.css" />
<script src="../../js/angular-ts.umd.js"></script>
<script src="../../js/angular-css.umd.js"></script>
</head>
<body ng-app="angular.css" ng-cloak data-example="context-menu-sides">
<main class="context-menu-sides visual-example">
<div
ng-context-menu
ng-repeat="side in ['inline-start','left','top','bottom','right','inline-end']"
>
<div ng-bind="side"></div>
<menu side="{{ side }}" aria-label="{{ side }} actions">
<button>Back</button>
<button>Forward</button>
<button>Reload</button>
</menu>
</div>
</main>
</body>
</html>
Right To Left
View source
<!doctype html>
<html lang="ar" dir="rtl">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>AngularCSS Context Menu Rtl</title>
<link rel="stylesheet" href="../../css/preflight.css" />
<link rel="stylesheet" href="../../css/angular.css" />
<link rel="stylesheet" href="../example.css" />
<script src="../../js/angular-ts.umd.js"></script>
<script src="../../js/angular-css.umd.js"></script>
</head>
<body
ng-app="angular.css"
ng-cloak
ng-init="lastAction='لا شيء'"
data-example="context-menu-rtl"
>
<main class="visual-example">
<div ng-context-menu>
<div>انقر بزر الفأرة الأيمن هنا</div>
<menu aria-label="إجراءات المتصفح">
<section>
<button ng-click="lastAction='رجوع'">
رجوع
<kbd>Alt+Right</kbd>
</button>
<button disabled>
للأمام
<kbd>Alt+Left</kbd>
</button>
<button ng-click="lastAction='إعادة تحميل'">
إعادة تحميل
<kbd>Ctrl+R</kbd>
</button>
</section>
<hr />
<details>
<summary>المزيد من الأدوات</summary>
<menu>
<button ng-click="lastAction='حفظ الصفحة'">حفظ الصفحة...</button>
<button ng-click="lastAction='أدوات المطور'">أدوات المطور</button>
</menu>
</details>
</menu>
</div>
<output class="context-menu-output" aria-live="polite">
الإجراء الأخير: <span ng-bind="lastAction"></span>
</output>
</main>
</body>
</html>
Installation
Install AngularCSS, load its stylesheet, and include the angular.css module in your AngularTS application. See Installation for the complete setup.
This component’s root directive is [ng-context-menu]. Importing the package registers it with the AngularCSS angular.css module; there is no per-component JavaScript registration step.
Anatomy
Directive selectors
ng-context-menu
Semantic structure
A context menu root requires one focusable trigger and one menu. The root directive inspects semantic sections, fieldsets, buttons, separators, keyboard hints, and nested details; no child directives or anatomy classes are required.
API
Attributes and state
| Attribute | Access | Purpose |
|---|---|---|
align | Input/output | Cross-axis alignment: start, center, or end. |
align-offset | Input | Additional alignment offset in CSS pixels. |
aria-checked | Input/output | ARIA relationship or state. |
aria-controls | Output | ID of the element controlled by a trigger. |
aria-disabled | Input/output | Semantic disabled state. |
aria-expanded | Output | Open or expanded state exposed to assistive technology. |
aria-haspopup | Output | Type of popup controlled by the trigger. |
aria-hidden | Output | Whether generated or collapsed content is hidden from assistive technology. |
dir | Input | Text and interaction direction: ltr or rtl. |
disabled | Input | Disables native or component interaction. |
open | Input | Initial or controlled open state. |
role | Output | Explicit semantic role when native HTML does not provide one. |
side | Input/output | Physical placement: left, top, bottom, or right. |
side-offset | Input | Distance from the invocation point in CSS pixels. |
tabindex | Input/output | Keyboard focus order for composite descendants. |
Input attributes are read from authored HTML. Output attributes are maintained by AngularCSS for CSS and testing. Input/output attributes may be authored for a controlled initial state and are then synchronized by the directive.
CSS custom properties
| Variable | Purpose |
|---|---|
--context-menu-available-height | Component styling variable. |
--context-menu-left | Component styling variable. |
--context-menu-top | Component styling variable. |
DOM events
angularcss:context-menu-select
Native DOM events continue to work normally. AngularTS event directives such as
ng-click and ng-keydown, plus the data-change model callback, remain application-owned.
Behavior
The directive owns right-click and keyboard disclosure, cursor-relative side placement with viewport collision constraints, menu and submenu focus movement, disabled-item skipping, Escape and outside dismissal, direction-aware submenu keys, semantic roles, and open-state reflection. AngularTS remains responsible for command execution, checkbox and radio values, controlled application state, and structural rendering.
AngularCSS does not replace AngularTS interpolation, bindings, structural directives, form controllers, validation, or application state.
Accessibility
Give the trigger and menu useful accessible names. The trigger exposes aria-haspopup, aria-controls, and expanded state; items receive menuitem, menuitemcheckbox, or menuitemradio roles; groups and separators remain semantic; disabled items are skipped. Shift+F10 or the Context Menu key opens from the keyboard, arrow keys move focus, logical submenu keys follow text direction, and Escape restores focus.
Authored accessible names and relationships are preserved. Test the final composition with keyboard navigation and assistive technology because labels and content come from the application.
Customization
Target [ng-context-menu], semantic descendants, component classes, and generated state with ordinary CSS. Keep behavior and accessible state in the TypeScript directive; visual choices belong in the application stylesheet.
Read Customization for layer order, design tokens, state variants, and iframe demo isolation.
Feedback
Was this page helpful?
Glad to hear it! Please tell us how we can improve.
Sorry to hear that. Please tell us how we can improve.