Since Flutter 3.0, Flutter has supported macOS Desktop Apps Development officially.
I became interested in how Flutter could be used to create typical features of macOS apps. For example, one of the distinct macOS app characteristics is the menu bar.
I looked into the Flutter repository issues on GitHub and checked the release notes. I found the pull request below.
The Flutter 3.0 release notes say the following.
Implements a PlatformMenuBar widget and associated data structures by @gspencergoog in https://github.com/flutter/flutter/pull/100274
From the Flutter 3.0 release notes
I noticed that Flutter could create a native Mac menu bar. So I made the sample code to see the details. The sample code is on GitHub.
Classes for the Menu Bar
The classes for the Menu Bar are the following:
PlatformMenuBar
PlatformMenu
PlatformMenuItemGroup
PlatformMenuItem
You can create the typical macOS menu bar with Flutter as the following screen capture.

Create the menu bar
Use the PlatformMenuBar
class to create the menu bar. The PlatformMenuBar
class is a widget inherited from the StatefulWidget
class. I made the sample code for the menu bar with the PlatformMenuBar
class. At this time, the menu bar is empty.
class _MyHomePageState extends State<MyHomePage> {
@override
Widget build(BuildContext context) {
return PlatformMenuBar(
menus: <MenuItem> [
],
body: Center(
// 省略
),
);
}
}
Create the menus
Each of the menus, such as “File” menu, “Edit” menu, etc, are instances of the PlatformMenu
class. Therefore, you put them into the array and pass it to the menus
parameter of the PlatformMenuBar
class constructor.
return PlatformMenuBar(
menus: <MenuItem>[
PlatformMenu(/*省略*/), // Application Menu
PlatformMenu(/*省略*/), // File Menu
PlatformMenu(/*省略*/), // Edit Menu
PlatformMenu(/*省略*/), // View Menu
PlatformMenu(/*省略*/), // Window Menu
],
body: Center(
),
);
The Application menu
There are two standard menus that every macOS apps have:
- the Apple menu
- the Application menu
The macOS manage the Apple menu. Unfortunately, the application can’t modify its items.
The Application menu, situated next to the Apple menu, has the foreground application’s name as its title.
The menus’ order corresponds to the array’s order passed into the PlatformMenuBar
class constructor. The first item of the array is an application menu.
The menu title and items
You specify the menu title to the label
parameter and items to the menus
parameter.
For example, the following code creates the File
menu with only the item New
.
PlatformMenu(
label: 'File',
menus: <MenuItem>[
PlatformMenuItemGroup(
members: <MenuItem>[
PlatformMenuItem(
label: 'New',
),
],
),
],
),
The general macOS App menu structure
The menu structure of a typical Mac application looks like this.
- Apple Menu
- Application Menu
- File Menu
- Edit Menu
- View Menu
- App own menus
- Window Menu
- Help Menu
However, it does not necessarily mean that the menu structure has to be exactly like this, so Flutter doesn’t create menus automatically.
When you don’t manually create the menus, the Apple and Application menus are generated automatically. However, Flutter doesn’t automatically generate the items in the Application menu.
The Human Interface Guidelines explain the general menu structure.

Create the separators
In AppKit, menu items and separators are instances of the NSMenuItem
class. Therefore, AppKit treats the separator as a menu item.
It is different in the Flutter. The separator divides the items within the menu into distinct groups. So, for example, the menu has two separators, and it is considered as three groups.
- Item 1
- Item 2
- Separator
- Item 3
- Item 4
- Separator
- Item 5
You can use PlatformMenuItemGroup
class to create the group. A code for the above example is the following.
PlatformMenu(
label: 'MyMenu',
menus: <MenuItem>[
PlatformMenuItemGroup(
members: <MenuItem>[
PlatformMenuItem(/*省略*/), // Item 1
PlatformMenuItem(/*省略*/), // Item 2
],
),
PlatformMenuItemGroup(
members: <MenuItem>[
PlatformMenuItem(/*省略*/), // Item 3
PlatformMenuItem(/*省略*/), // Item 4
],
),
PlatformMenuItemGroup(
members: <MenuItem>[
PlatformMenuItem(/*省略*/), // Item 5
],
),
],
),
The separator appears as a group delimiter.
Create the menu item
You can utilize the PlatformMenuItem
class to create individual menu items.
PlatformMenuItem(
label: 'Item Title',
),
The label
parameter represents the title of an item.
Implement the action when the item selected
You can assign an action to be executed upon item selection using the onSelected
parameter.
PlatformMenuItem(
label: 'Increment',
onSelected: () {
// メニューが選択されたときの処理
_incrementCounter();
},
),
In this example, the _incrementCounter()
method is executed when the Increment
menu item is selected.
Assign shortcut keys
You can specify the shortcut to the shortcut
parameter. The shortcut is a SingleActivator
class instance.
PlatformMenuItem(
label: 'Increment',
shortcut: const SingleActivator(LogicalKeyboardKey.keyI, meta: true),
onSelected: () {
_incrementCounter();
},
),
This code assigns the Command
and I
keys as the shortcuts.
LogicalKeyboardKey
class defines keys you can specify with the modifier key. Then, you pass the key and modifier key to the argument of the SingleActivator
class constructor. The following arguments are available, including those omitted.
Paramter | Modifier Key |
---|---|
control | Control Key |
shift | Shift Key |
alt | Option Key |
meta | Command Key |
Platform-specific menu items
You can utilize PlatformProvidedMenuItem
class to create the platform-specific menu items such as the Services
and Show All
in the application menu. The application couldn’t make them.
For example, the code to create the Services
menu item is the following.
PlatformMenuItemGroup(
members: <MenuItem>[
if (PlatformProvidedMenuItem.hasMenu(PlatformProvidedMenuItemType.servicesSubmenu))
const PlatformProvidedMenuItem(type: PlatformProvidedMenuItemType.servicesSubmenu),
],
),
The hasMenu()
method returns whether the menu item specified in the argument is supported.
You can specify the menu item you want to create to the type
argument of the `PlatformProvidedMenuItem` constructor. Flutter defines following macOS-specific menus at the writing time.
about
quit
servicesSubmenu
hide
hideOtherApplications
showAllApplications
startSpeaking
stopSpeaking
toggleFullScreen
minimizeWindow
zoomWindow
arrangeWindowsInFront
Flutter 3.0 defines only macOS-specific menu items, not for other platforms.
Sample Code
I uploaded the sample code to GitHub. Please see it for the actual code.