# Menus

### Desktop Application Menus

Positron includes a robust builder pattern for building top-level application menus (e.g., the Apple Menu bar on macOS or window-top file dropdown strip on Windows).

{% tabs %}
{% tab title="Add Item" %}

<pre class="language-javascript" data-line-numbers><code class="lang-javascript">const { app } = require('positron.js');
const { Menu, MenuItem } = require('positron.js/menu');

mainWindow.on("ready", () => {
  const applicationMenu = new Menu()
    .addItem(new MenuItem({
      label: 'File',
      items: [
        new MenuItem({ label: 'New File', channel: 'menu:file-new', payload: { type: 'text' }, key: 'n' }),
        new MenuItem({ label: 'Open...', channel: 'menu:file-open' }),
        new MenuItem({ label: 'Save Changes', channel: 'menu:file-save', key: 's' }),
        new MenuItem({ label: 'Quit', channel: 'menu:quit', key: "q", click: () => app.quit() })
      ]
    }))
    .addItem(new MenuItem({
      label: 'Edit',
      items: [
        new MenuItem({ label: 'Undo', channel: 'menu:edit-undo' }),
        new MenuItem({ label: 'Redo', channel: 'menu:edit-redo' })
      ]
    }));

  // Deploy configuration down to native window shell layer
<strong>  mainWindow.setMenu(applicationMenu);
</strong>});

// Capture native menu triggers globally in your main process
app.events.on('menu-action', (data) => {
  console.log(`[Menu Click Event] Channel: "${data.channel}" | Context Data:`, data.payload);
});
</code></pre>

{% endtab %}

{% tab title="Add Items" %}
{% code lineNumbers="true" %}

```javascript
const { app } = require('positron-core');
const { Menu, MenuItem } = require('positron-core/menu');

mainWindow.on("ready", () => {
  const applicationMenu = new Menu()
    .addItems([
    new MenuItem({
      label: 'File',
      items: [
        new MenuItem({ label: 'New File', channel: 'menu:file-new', payload: { type: 'text' }, key: 'n' }),
        new MenuItem({ label: 'Open...', channel: 'menu:file-open' }),
        new MenuItem({ label: 'Save Changes', channel: 'menu:file-save', key: 's' }),
        new MenuItem({ label: 'Quit', channel: 'menu:quit', key: "q", click: () => app.quit() })
      ]
    }),
    new MenuItem({
      label: 'Edit',
      items: [
        new MenuItem({ label: 'Undo', channel: 'menu:edit-undo', key: 'z' }),
        new MenuItem({ label: 'Redo', channel: 'menu:edit-redo', key: 'y' }),
        new Separator(),
        new MenuItem({ label: 'Cut', channel: 'menu:edit-cut', key: 'x' }),
        new MenuItem({ label: 'Copy', channel: 'menu:edit-copy', key: 'c' }),
        new MenuItem({ label: 'Paste', channel: 'menu:edit-paste', key: 'v' })
      ]
    })
    ])

  // Deploy configuration down to native window shell layer
  mainWindow.setMenu(applicationMenu);
});

// Capture native menu triggers globally in your main process
app.events.on('menu-action', (data) => {
  console.log(`[Menu Click Event] Channel: "${data.channel}" | Context Data:`, data.payload);
});
```

{% endcode %}

{% endtab %}
{% endtabs %}

#### MenuItem Options Reference

| Property    | Type               | Description                                                                                   |
| ----------- | ------------------ | --------------------------------------------------------------------------------------------- |
| `label`     | `String`           | The plain text display label rendered inside the dropdown.                                    |
| `channel`   | `String?`          | The unique application IPC channel name fired when clicked.                                   |
| `payload`   | `Object / String?` | Custom context parameters passed back up to `app.events` on select.                           |
| `key`       | `String?`          | Keyboard character shortcut accelerator (automatically paired with system command modifiers). |
| `separator` | `Boolean?`         | When `true`, ignores labels and produces a structural divider rule line.                      |
| `click`     | `Function?`        | Function to execute on click.                                                                 |
| `enabled`   | `Bool?`            | Is the menu item enabled?                                                                     |

#### Separator

{% tabs %}
{% tab title="Class" %}
{% code lineNumbers="true" %}

```javascript
const { Separator } = require('positron.js/menu')

menu.addItem(new Separator())
```

{% endcode %}
{% endtab %}

{% tab title="MenuItem" %}
{% code lineNumbers="true" %}

```javascript
const { MenuItem } = require('positron.js/menu')

menu.addItem(new MenuItem({ separator: true }))
```

{% endcode %}
{% endtab %}
{% endtabs %}

### Context Menus

Context menus work very similarly to application menus as they also use `positron.js/menu`.

<pre class="language-javascript" data-line-numbers><code class="lang-javascript">const { Menu, MenuItem } = require('positron.js/menu');

const contextMenu = new Menu()
    .addItem(new MenuItem({
        label: 'Set Background Color',
        click: async () => {
            const color = await mainWindow.prompt("Enter a background color (e.g., 'lightblue' or '#ff0000'):", "lightblue")
            if (!color) return mainWindow.alert("No color entered. Background color change cancelled.")
            const res = await mainWindow.evaluateJavaScript(`document.body.style.backgroundColor = '${color}'; "Page background color changed to ${color}!"`)
            console.log("Result:", res.result)
        }
    }))
    .addItem(new MenuItem({
        label: 'Set User Agent',
        click: async () => {
            const userAgent = await mainWindow.prompt("Enter a new user agent string:", "My Custom User Agent/1.0")
            if (!userAgent) return mainWindow.alert("No user agent entered. User agent change cancelled.")
            mainWindow.setUserAgent(userAgent)
            const res = await mainWindow.evaluateJavaScript(`document.documentElement.innerHTML += "&#x3C;h1>Current User Agent:&#x3C;/h1>&#x3C;p>" + navigator.userAgent + "&#x3C;/p>"; navigator.userAgent;`)
            console.log("New User Agent:", res)
        }
    }))

<strong>mainWindow.setContextMenu(contextMenu)
</strong>
app.events.on('context-menu-action', (data) => {
  console.log(`[Context Menu Click Event] Channel: "${data.channel}" | Context Data:`, data.payload);
});
</code></pre>


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://positronjs.gitbook.io/v1/commands/menus.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
