{"id":19825649,"url":"https://github.com/nkappler/ctxmenu","last_synced_at":"2026-01-21T15:08:50.570Z","repository":{"id":45392604,"uuid":"164878619","full_name":"nkappler/ctxmenu","owner":"nkappler","description":"Tiny and customizable context menu generator","archived":false,"fork":false,"pushed_at":"2025-02-12T15:23:46.000Z","size":930,"stargazers_count":49,"open_issues_count":5,"forks_count":6,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-04-16T22:04:52.315Z","etag":null,"topics":["context-menu","contextmenu","customizable","easy-to-use","javascript","javascript-library","no-dependencies","pressandhold","right-click","standalone","submenu","tiny"],"latest_commit_sha":null,"homepage":"https://nkappler.de/ctxmenu/","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/nkappler.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2019-01-09T14:31:52.000Z","updated_at":"2025-04-07T11:33:35.000Z","dependencies_parsed_at":"2023-12-25T23:31:29.539Z","dependency_job_id":"ed6ad054-7859-42eb-ba55-013a516b8765","html_url":"https://github.com/nkappler/ctxmenu","commit_stats":null,"previous_names":[],"tags_count":23,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nkappler%2Fctxmenu","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nkappler%2Fctxmenu/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nkappler%2Fctxmenu/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nkappler%2Fctxmenu/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/nkappler","download_url":"https://codeload.github.com/nkappler/ctxmenu/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":251889935,"owners_count":21660415,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["context-menu","contextmenu","customizable","easy-to-use","javascript","javascript-library","no-dependencies","pressandhold","right-click","standalone","submenu","tiny"],"created_at":"2024-11-12T11:08:18.691Z","updated_at":"2026-01-21T15:08:50.564Z","avatar_url":"https://github.com/nkappler.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# ctxmenu.js ![Icon](https://raw.githubusercontent.com/nkappler/ctxmenu/master/docs/favicon.png)[![npm](https://img.shields.io/npm/v/ctxmenu.svg)](https://www.npmjs.com/package/ctxmenu) [![npm](https://img.shields.io/npm/types/ctxmenu.svg)](https://raw.githubusercontent.com/nkappler/ctxmenu/master/index.d.ts)\n\n## Tiny* and customizable context menu generator.\n\u003csup\u003e* \u003c3kB minified and gzipped\u003c/sup\u003e\n\n[DEMO](https://nkappler.github.io/ctxmenu)\n\n#### Table of contents\n[Features](#features)\\\n[Installation](#installation)\\\n[Menu Definition](#menu-definition)\\\n[Item Types](#item-types) \\\n[API](#api) \\\n[Custom Events](#custom-events) \\\n[Customize](#customize) \\\n[Contributing](#contributing)\n\n## Screenshot\n![Screenshot](https://raw.githubusercontent.com/nkappler/ctxmenu/master/docs/features.png)\n\n## Features\n\n- Create custom context menus for every browser.\n- Style the context menu with css.\n- No dependencies.\n- Callback to customize based on event properties _(Cursor position, etc.)_\n- Different menu items: headings, anchors, action items, dividers and submenus\n- Interactive menu items can be disabled\n\n\n## Installation\n\n### with npm:\nInstall ctxmenu\n```shell\nyour_project\u003e npm install -s ctxmenu\n```\n\nImport ctxmenu:\n```typescript\nimport { ctxmenu } from \"ctxmenu\";\n```\n\n### without npm\nctxmenu.js is also available as a standalone version.\nto use it, just download and link ctxmenu.js or ctxmenu.min.js in your websites header.\n\n```html\n\u003chead\u003e\n    \u003c!-- ... --\u003e\n\n    \u003cscript src=\"../ctxmenu.js\"\u003e\u003c/script\u003e\n\n\u003c/head\u003e\n```\n\n## Menu Definition\n\nMenu definitions are used to describe the content of a context menu. A menu definition is an array of objects, where each object defines a single item in the menu.\n\nExample:\n\n![Screenshot](https://raw.githubusercontent.com/nkappler/ctxmenu/master/docs/simpleMenu.png)\n\n```javascript\nvar menuDefinition = [\n    { text: \"Heading\" },\n    {\n        text: \"Action Item\",\n        action: () =\u003e alert(\"Hello World!\")\n    },\n    { isDivider: true },\n    {\n        text: \"Anchor Item\",\n        href: \"\",\n        disabled: true\n    }\n]\n```\n\n## Item Types\n\n[Heading](#heading-item) \\\n[Anchor](#anchor-item) \\\n[Action Item](#action-item) \\\n[Submenu](#submenu-item)\\\n[Divider](#divider-item)\n\n### Heading Item\n\nThis is a heading item which displays a `text` and optionally shows a `tooltip` when hovering over it. If you need finer control over the content of the menu item, you can supply your own HTML string by using the `html` property instead of `text`. Alternatively you can also supply an HTMLElement JavaScript Object. For all properties you can supply the value directly or a factory function which will be called just before the menu is opened (i.e. on right click). You can also supply a URL or Data URL to an image used as `icon` for the menu item. Recommended resolution is 18×18px. \\\nFor more information about the `EventRegistry`, see [Custom Events](#custom-events). With the `attributes` record you can define arbitrary attributes for the list item, like you can with the `Element.setAttribute` browser API, for example, `id`, `class` or data attributes.\n\n\u003e [!NOTE]\n\u003e Keep in mind that with the `attributes` record you can overwrite other config options like `style` or `tooltip` for example\n\n```typescript\n{\n    text?: string | () =\u003e string,\n    tooltip?: string | () =\u003e string,\n    html?: string | () =\u003e string,\n    element?: HTMLElement | () =\u003e HTMLElement,\n    icon?: string | () =\u003e string,\n    style?: string | () =\u003e string,\n    events?: EventRegistry | () =\u003e EventRegistry,\n    attributes?: Record\u003cstring, string\u003e | () =\u003e Record\u003cstring, string\u003e\n}\n```\n\n⚠ NOTE: _All other menu items (except the divider item) derive from this and can have at least these properties_\n\n### Anchor Item\n\nThis is an interactive item which implements an anchor tag (`\u003ca\u003e`) and will redirect to a given URL (`href`).\n\n```typescript\n{\n    /*...Standard Props */\n\n    /** URL */\n    href: string | () =\u003e string,\n\n    /** https://www.w3schools.com/tags/att_a_target.asp */\n    target?: string | () =\u003e string,\n\n    /** defaults to false */\n    disabled?: boolean | () =\u003e boolean\n}\n```\n\n### Action Item\n\nThis is an interactive item which will execute a given callback function when clicked.\nThe callback receives the event as parameter, so you can access the Action Item List Element via `e.currentTarget`.\n\n```typescript\n{\n    /*...Standard Props */\n\n    /** callback fired when the item is clicked */\n    action: (event: MouseEvent) =\u003e void,\n\n    /** defaults to false */\n    disabled?: boolean | () =\u003e boolean\n}\n```\n\n### Submenu Item\n\nThis is an interactive item which holds another [menu definition](#menu-definition). You can create infinitely deep nested submenus.\nWith `subMenuAttributes` you define HTML attributes for the submenu container (the UL element), with `attributes` you can define those for the list item itself.\n\n```typescript\n{\n    /*...Standard Props */\n\n    /** Submenu Definition, */\n    subMenu: Array | () =\u003e Array,       // A menu definition\n\n    /** Attribute record for the submenu container */\n    subMenuAttributes: Record\u003cstring, string\u003e | () =\u003e Record\u003cstring, string\u003e\n\n    /** defaults to false */\n    disabled?: boolean | () =\u003e boolean  // default false\n}\n```\n\n### Divider Item\n\nThis is a divider item which draws a horizontal line.\n\n```typescript\n{ isDivider: true }\n```\n\n## API\n\nThis library exports a singleton object `ctxmenu`.\nIn the standalone version the singleton is a global variable (`window.ctxmenu`).\nIt has the following six APIs:\n\n[attach](#ctxmenuattach)\\\n[update](#ctxmenuupdate)\\\n[delete](#ctxmenudelete)\\\n[show](#ctxmenushow)\\\n[hide](#ctxmenuhide)\\\n[setNonce](#ctxmenusetnonce)\n\n### Interfaces\n[CTXConfig](#ctxconfig)\n\n### `ctxmenu.attach`\n```typescript\nctxmenu.attach(target: string, ctxmenu: Array, config?: CTXConfig)\n```\n\nThe `attach` method is used to bind a context menu to any DOM Node and takes the following arguments:\n- `target` - A selector string to define the target node (eg `'body'`, or `'#someID'`)\n- `ctxmenu` - An Array of objects defining the menu layout. See [Menu Definition](#menu-definition).\n- `config?` -  A config object, See [CTXConfig](#ctxconfig).\n\n### `ctxmenu.update`\n```typescript\nctxmenu.update(target: string, ctxmenu?: Array,  config?: CTXConfig)\n```\n\nThe update method is used to update an existing context menu. You can pass `undefined` for each optional parameter in order to not change it. If you pass a partial [CTXConfig](#ctxconfig) object, only the specified members will be overwritten.\n\n`update` takes two or three arguments:\n- `target` - the selector string to define the target element\n- `ctxmenu` - the updated menu definition.  _(may be undefined when only updating the config)_\n- `config?` - A config object, See [CTXConfig](#ctxconfig).\n\n\u003e [!NOTE]\n\u003e If you try to update a menu which does not exist, it will silently be [attached](#ctxmenuattach) instead.\n\n### `ctxmenu.delete`\n```typescript\nctxmenu.delete(target: string)\n```\nThe delete method is used to delete a context menu and only takes the `target` selector string.\n\n### `ctxmenu.show`\n```typescript\nctxmenu.show(ctxmenu: Array, e: MouseEvent | HTMLElement)\n```\nThe `show` method can be used to show a context menu without using the [`attach`](#ctxmenuattach) method to set up a contextmenu for specific elements first. You need to pass the original event or a target element, which will be used to calculate the menu's position.\n\nThis may be useful when integrating with other libraries or frameworks that already provide a contextmenu handler or when trying to show a context menu on a different user interaction (for example showing a context menu when left-clicking a button).\n\n⚠️**Positioning of the menu:** If the second parameter you pass is of type `MouseEvent`, the menu will appear at the cursors position, if it is of type `HTMLElement` it will appear next to the element. See [#36](https://github.com/nkappler/ctxmenu/issues/36)\n\n⚠️ **Event propagation:** When passing a target element, you will need to stop the propagation of the event to prevent the context menu from being immediately closed again:\n\n```typescript\nclickHandler(e: MouseEvent) {\n  e.stopPropagation();\n  ctxmenu.show([ ... /* menu definition */ ], e.target);\n}\n```\n\n### `ctxmenu.hide`\n```typescript\nctxmenu.hide()\n```\nHide any open context menu.\n\n### `ctxmenu.setNonce`\n```typescript\nctxmenu.setNonce(nonce: string)\n```\nSet a CSP (Content Security Policy) nonce to be used for ctxmenus style element. This is useful when you have a strict CSP that requires nonces for inline styles.\n\n\u003e [!IMPORTANT]\n\u003e `setNonce` must be called **before the first menu is shown**, otherwise you have to expect rendering issues due to missing styles. If required by your CSP, make sure to call this method early in your application initialization, ideally before any `attach` calls.\n\nExample:\n```typescript\n// Set a nonce for all menus (must be called before showing any menu)\nctxmenu.setNonce('your-csp-nonce-here');\n\n// Attach menus as usual\nctxmenu.attach('#myElement', menuDefinition);\n```\n\n## CTXConfig\n\nWith this interface you can define __lifecycle events__ and __attributes__ for a context menu via the [attach](#ctxmenuattach) and [update](#ctxmenuupdate) methods.\n\n```typescript\n    onBeforeShow?: (menu: CTXMenu, event?: MouseEvent) =\u003e CTXMenu;\n    onShow?: (dom: HTMLUListElement) =\u003e void;\n    onBeforeHide?: (dom: Element) =\u003e void;\n    onHide?: (dom: Element) =\u003e void;\n    attributes?: Record\u003cstring, string\u003e;\n```\n\nThe `onBeforeShow` method can be used to change the menu definition just before it is shown. This can be useful to customize the menu based on the event properties (for example, the cursor position). The function must return a valid menu definition.\n\nThe `onShow` method can be used to execute code after the menu is attached to the DOM. This can be useful to execute code that depends on the menu being visible (for example, to focus an input field). Gets passed a reference to the DOM Element representing the context menu.\n\nThe `onBeforeHide` method can be used to execute code just before the menu is detached from DOM. This can be useful to execute code that depends on the menu being visible (for example, to save the state of the menu). Will be called for any submenu that is closed as well. Gets passed a reference to the DOM element which will be removed.\n\nThe `onHide` method can be used to execute code after the menu is hidden. This can be useful to execute code that depends on the menu being hidden (for example, to reset the state of the menu). Will be called for any submenu that is closed as well. Gets passed a reference to the DOM element which has been removed.\n\nThe `attributes` record can be used to define arbitrary attributes for the menu container (the UL element), like you can with the `Element.setAttribute` browser API, for example, `id`, `class` or data attributes.\n\n## Custom Events\n\nEvery Menu Item has an optional `events` property:\n```typescript\n{\n    events?: EventRegistry | () =\u003e EventRegistry\n}\n```\n\nThe `EventRegistry` is a map of event handlers. For each event you can either specify the event listener directly, or an object containing the `listener` and an optional `options` ([EventListenerOptions](https://developer.mozilla.org/en-US/docs/Web/API/EventTarget/addEventListener#syntax)) object:\n\n```typescript\n{\n    text: \"Hover me!\",\n    events: {\n        mouseenter: (e) =\u003e e.target.style.animation = \"blinker 1s linear infinite\",\n        mouseleave: {\n            listener: (e) =\u003e e.target.style.animation = \"\",\n            options: {\n                passive: true\n            }\n        }\n    }\n}\n```\n\n## Customize\n\nctxmenu.js uses the following css classes which you might want to overwrite:\n\n```css\n.ctxmenu                /* the main menu div */\n.ctxmenu li             /* any menu item */\n.ctxmenu li.disabled    /* any disabled menu item */\n.ctxmenu li.divider     /* any horizontal divider */\n.ctxmenu li.interactive /* any interactive item (anchor, action item, submenu)*/\n.ctxmenu li.submenu     /* any menu item that has a submenu */\n```\n\n## Contributing\n\n### Step 1: Setup\nAfter cloning the repo, run `npm install`. This will install all dev-dependencies and also should transpile the library to javascript, as the tests use the transpiled files to be as close to a real-world setup as possible.\n\nUntil you do this step, you might see errors in the test files.\n\nAfter this step, these directories should be generated in the repository:\n`dist`, `standalone` and `node_modules`.\n\nIf you don't see the `standalone` or `dist` directory, run the build command manually:\n\n### Step 2: Build and Test Commands\n- `npm run build` transpiles all source files into javascript once.\n- `npm run test` launches the build in watch mode and starts the test proxy at [localhost:8888](http://localhost:8888)\n- `npm run dev` transpiles all source files in watch mode, open the demo page (`docs/index.html`) in your browser to test your changes manually.\n\n### Step 3: Test your changes\nPlease test your changes before opening a PR. To test your changes locally, run `npm run dev`. This will transpile the typescript source files. You can now open the `docs/index.html` file in your browser to test your changes manually.\n\n### Step 4: Open a Pull Request\nYour PR should describe your use case and your changes in detail and must include automated tests. You can add your tests cases in the `test/*.test.ts` files.\n\nIf you feel that your modification should be part of the demo page, add an example to `test/demo.ts`.\nThis file will be transpiled by any of the build commands into `/docs/demo.js`, don't modify the JavaScript file directly, or the changes will be overwritten.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fnkappler%2Fctxmenu","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fnkappler%2Fctxmenu","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fnkappler%2Fctxmenu/lists"}