By main menu we mean this. This is Atom's main menu, but we want to add something like this for our application. To do this, let's create a new file called mainmenu.js. Let's require app and menu from Electron.
The typical application menus on Windows and Mac are quite a bit different, so from the get-go we're going to check if we're running on Windows. In Electron applications, it's not uncommon to have special handling for each platform.
There's nothing special Electron going on here, this is the typical Node.js way you'd check for it. We're going to export a function that will call setMainMenu. The first thing we're going to do is we'll set up an array here called template, and we're going to define the far-left menu, also called the application menu sometimes on Mac.
It's always the name of the application, on Windows it's usually just File is the most far-left one. We'll just add a quick menu item to it. Electron menus are defined as arrays of objects, so for our application menu we'll have an object here, and for our label, we'll check if it's Windows.
Because if it is Windows we want to call file, if it is a Mac, what we're going to do is we're going to call app.getName. This is an Electron method that dynamically returns the name of your application as defined in your package.json.
Then for its menu items, we pass this submenu property an array of objects. If we label here, we'll check if it's Windows. Windows generally calls it exit, and Mac calls it quit, and by convention Mac also passes the application name.
For every menu item, Electron allows us to define an accelerator, which is just another word for a hot key for your menu item action. We'll define an accelerator here, and we'll say if it's Windows, the standard hot key for quitting an app is alt-F4, on Mac we're going to do command or ctrl+Q.
We do command or ctrl here just in case maybe somebody's in a weird keyboard, or they're on a Linux machine, and basically command will be used on Mac, and anywhere command is not available, ctrl will be used instead for this hot key.
This string format is an Electron defined format that you can read about more in the API documentation for menus. It's pretty intuitive and straightforward. Next we'll define a click handler. This function will be called when either the accelerator is activated from the keyboard, or when they manually click on the menu item.
In here we'll call the quit method. We have our template done, we have a single top menu item defined with a single menu item underneath it, so now we need to set it on the application, the main menu.
First, we need to call buildFromTemplate, and we'll pass it our template. This will take this data structure and convert it to the data structures that Electron needs to actually construct your menu.
Then we'll pass the output of that to menu.setApplicationMenu, which will actually set your application's menu. Now let's require this in our main.js, jump in here, and we'll require and set mainMenu. We'll want to call this in our onReady handler for our app, because it won't work before then.
OK, let's run our npm start script and check it out, npm start. We can see this is our application menu which on Mac is just going to say Electron, and whenever you're running Electron in development, this is always going to say Electron regardless of what you have in your package.json.
When you actually package and compile your app into an executable file, this will have your actual application name here. This is our menu item that we defined, we can see that it's working.
This is our label that we defined, and the hot key that we defined as well. If we click on that now, we can see that it quits our application. Let's start it again, and we'll try the command+Q short cut, and that works as well. Now let's add an edit menu to our main menu. Back here in our template we're going to add another object here, call this edit. Then add our submenu array here, edit menus are petty standard cross-platform, so we won't need any cross-platform checks here.
Typically edit menus contain items like copy, paste, etc., instead of manually reimplementing all of that functionality, Electron gives us the ability to specify a role on a menu item, to designate a standard menu item without any custom functionality.
Let's add some of these role menu items. First one we'll do role is undo, and then we'll do redo. Typically, at this point in a menu item there is a separator. This won't do anything, it will just be a visual line that separates the undo and redo from the rest of the menu items.
Then we'll add cut, copy, paste, and select all. There's lots of different roles that you can specify for menu items. I encourage you to check out Electron's documentation to see them all. A few of them are platform-specific, most are general for all of them.
OK, let's add a text input to our index.html so that we can try out all these different edit menu items. I'll just correct the misspelling separator then run npm start to check out our edit menu.
Here's the edit menu that we defined, and we can see that Electron filled in the details based on the role that we provided. For example, we have undo here, and it's command+Z, on Windows it' going to be ctrl-Z. Redo on Windows it's going to be ctrl-Y, on Mac it's shift-command+Z.
Electron has taken care of all the platform specific details here. Also, this is provided by default from MacOS. Let's try out our edit menu functionality here in this input. Do test, command+A selects all, and do command+C to copy it. Command+V paste, we can see it's working in that input.
This is a basic overview of what's possible with a menu API. There's a lot more it can do including nested submenus, checkbox menu items, custom icons and more. Take a look at the Electron docs on the menu API to see what's possible.