# How Context Menu Integration for the Markdown Toggle Feature Works in Markdown Here

> Discover how Adam-P Markdown Here integrates its context menu to toggle Markdown. Learn about event messaging and content script injection in this in-depth technical guide.

- Repository: [Adam Pritchard/markdown-here](https://github.com/adam-p/markdown-here)
- Tags: internals
- Published: 2026-03-05

---

**The Markdown Toggle context menu integration registers a browser context menu item restricted to editable fields, which triggers the same `markdownToggle()` function used by the toolbar button by injecting content scripts and dispatching a `button-click` runtime message.**

The adam-p/markdown-here extension provides a seamless way to convert Markdown syntax to rendered HTML within web-based text editors. Understanding how the context menu integration for the Markdown Toggle feature functions requires examining the interaction between background scripts, content scripts, and the core toggle logic distributed across the repository.

## Registering the Context Menu in backgroundscript.js

The context menu entry is established when the extension initializes. In [`src/chrome/backgroundscript.js`](https://github.com/adam-p/markdown-here/blob/main/src/chrome/backgroundscript.js), the registration occurs within the `chrome.runtime.onInstalled` listener to ensure the menu item is created immediately after installation or updates.

### Creating the Editable Context Menu Item

The extension creates a menu item specifically targeting editable web content:

```javascript
chrome.contextMenus.create({
  id: 'markdown-here-context-menu',
  contexts: ['editable'],
  title: Utils.getMessage('context_menu_item')
});

```

The `contexts: ['editable']` parameter restricts the menu to appear only when users right-click inside text input areas, such as Gmail compose windows, GitHub comment boxes, or generic HTML textareas. This prevents the menu from cluttering non-editable page contexts.

## Handling Context Menu Clicks

When a user selects the **Markdown Here** entry from the context menu, the `chrome.contextMenus.onClicked` listener invokes the `handleActionClick` function to manage the execution flow.

### The handleActionClick Function

Located in [`src/chrome/backgroundscript.js`](https://github.com/adam-p/markdown-here/blob/main/src/chrome/backgroundscript.js) (lines 77-106), `handleActionClick` performs three critical operations:

1. **Detects the active tab context** to determine if the user is on the extension's options page
2. **Injects content scripts** using `Injector.injectScripts(tab.id)` if the scripts are not already present in the target tab
3. **Dispatches the activation message** with the payload `{ action: 'button-click', info: info }`

```javascript
chrome.contextMenus.onClicked.addListener(async function(info, tab) {
  await handleActionClick(tab, info);
});

```

This architecture ensures that the content scripts—including [`src/chrome/contentscript.js`](https://github.com/adam-p/markdown-here/blob/main/src/chrome/contentscript.js) and the core [`markdown-here.js`](https://github.com/adam-p/markdown-here/blob/main/markdown-here.js) bundle—are loaded before attempting to trigger the toggle functionality.

## Processing the Message in contentscript.js

The content script acts as the intermediary between the background script's message and the actual toggle implementation.

### Listening for the button-click Action

In [`src/chrome/contentscript.js`](https://github.com/adam-p/markdown-here/blob/main/src/chrome/contentscript.js), a runtime message listener waits for the specific action type:

```javascript
chrome.runtime.onMessage.addListener(function (request, sender, sendResponse) {
  if (request && request.action === 'button-click') {
    markdownToggle();
  }
});

```

By checking for `request.action === 'button-click'`, the content script ensures that only legitimate toggle commands from the toolbar button or context menu trigger the conversion logic.

## Executing the Markdown Toggle Logic

The actual conversion between Markdown source and rendered HTML resides in [`src/common/options.js`](https://github.com/adam-p/markdown-here/blob/main/src/common/options.js) within the `markdownToggle()` function (lines 324-340).

### State Detection and Rendering

The `markdownToggle()` function determines the current editor state by checking for the presence of the `.mdh-mirror` CSS class. Based on this detection, it either:

- Calls `MarkdownRender.markdownRender` to convert Markdown syntax to formatted HTML
- Restores the original Markdown source from the mirror element

The function also synchronizes the toolbar button state and persists the current view preference to `OptionsStore`, ensuring consistency across multiple toggle operations.

## Complete Execution Flow Example

The following code illustrates the full path from context menu interaction to Markdown conversion:

```javascript
// Step 1: Background script receives the context menu click
chrome.contextMenus.onClicked.addListener(async (info, tab) => {
  await handleActionClick(tab, info);
});

// Step 2: Background script sends activation message to content script
chrome.tabs.sendMessage(tab.id, { action: 'button-click', info: info });

// Step 3: Content script receives message and triggers the toggle
chrome.runtime.onMessage.addListener((request) => {
  if (request.action === 'button-click') {
    markdownToggle(); // Defined in src/common/options.js
  }
});

```

This unified message-passing approach ensures that both the browser action toolbar button and the right-click context menu execute identical conversion logic.

## Summary

- **Menu Registration**: [`src/chrome/backgroundscript.js`](https://github.com/adam-p/markdown-here/blob/main/src/chrome/backgroundscript.js) creates a context menu item with ID `markdown-here-context-menu` restricted to `editable` contexts using `chrome.contextMenus.create()`
- **Script Injection**: The `handleActionClick` function ensures content scripts are injected via `Injector.injectScripts()` before dispatching messages
- **Message Passing**: Both toolbar and context menu triggers send a `button-click` action to the content script
- **Unified Logic**: The `markdownToggle()` function in [`src/common/options.js`](https://github.com/adam-p/markdown-here/blob/main/src/common/options.js) handles the actual Markdown rendering and state management for both entry points

## Frequently Asked Questions

### Where is the context menu item for Markdown Toggle defined?

The context menu item is defined in [`src/chrome/backgroundscript.js`](https://github.com/adam-p/markdown-here/blob/main/src/chrome/backgroundscript.js) using the `chrome.contextMenus.create()` API during the `chrome.runtime.onInstalled` event. It uses the ID `markdown-here-context-menu` and is restricted to `editable` contexts so it only appears in text input fields.

### Why does the context menu only appear on certain web pages?

The menu item specifies `contexts: ['editable']` in its creation options, which limits its appearance to editable HTML elements such as textareas and rich text editors. This prevents the menu from displaying when right-clicking on static text or images.

### How does the context menu trigger the same conversion as the toolbar button?

Both activation methods send an identical runtime message with the action `button-click` to the content script. The listener in [`src/chrome/contentscript.js`](https://github.com/adam-p/markdown-here/blob/main/src/chrome/contentscript.js) receives this message and calls `markdownToggle()` from [`src/common/options.js`](https://github.com/adam-p/markdown-here/blob/main/src/common/options.js), ensuring the same rendering logic executes regardless of how the feature is invoked.

### What happens if content scripts are not loaded when the context menu is used?

The `handleActionClick` function in [`src/chrome/backgroundscript.js`](https://github.com/adam-p/markdown-here/blob/main/src/chrome/backgroundscript.js) checks the tab's script injection state and calls `Injector.injectScripts(tab.id)` to load [`contentscript.js`](https://github.com/adam-p/markdown-here/blob/main/contentscript.js) and its dependencies before sending the activation message. This guarantees the toggle functionality works even on freshly loaded pages.