アプリケーションのメニューバーを作る方法を解説します。
Tauri v2 では、Rust バックエンドまたは JavaScript フロントエンドのどちらからでもネイティブメニューを作成できます。
前提条件
Permissions (権限) の設定
src-tauri/capabilities/default.json に menu:default 権限を追加します。
{
"permissions": [
...,
"core:menu:default"
]
}
1. フロントエンドから作成する (TypeScript)
Menu.new() を使用してメニューを作成し、setAsAppMenu() でアプリケーション全体のメニューとして設定します。
シンプルな記法(オブジェクト形式)
import { Menu } from '@tauri-apps/api/menu';
const menu = await Menu.new({
items: [
{
text: 'ファイル',
items: [
{
id: 'open',
text: '開く',
action: () => {
console.log('開くがクリックされました');
}
},
{
id: 'save',
text: '保存',
action: () => {
console.log('保存がクリックされました');
}
}
]
}
]
});
// アプリケーション全体のメニューとしてセット
await menu.setAsAppMenu();
クラスを使用した記法
import { Menu, Submenu, MenuItem } from '@tauri-apps/api/menu';
// 1. ファイルメニューの項目を作成
const openItem = await MenuItem.new({
id: 'open',
text: '開く',
action: () => {
console.log('開くがクリックされました');
}
});
const saveItem = await MenuItem.new({
id: 'save',
text: '保存',
action: () => {
console.log('保存がクリックされました');
}
});
// 2. "ファイル" サブメニューを作成し、項目を追加
const fileMenu = await Submenu.new({
text: 'ファイル',
items: [openItem, saveItem]
});
// 3. アプリケーションメニューを作成
const menu = await Menu.new({
items: [fileMenu]
});
// 4. アプリケーション全体のメニューとしてセット
await menu.setAsAppMenu();
参考: Menu API リファレンス
2. バックエンドから作成する (Rust)
Rust 側でメニューを定義し、アプリケーション起動時に設定する方法です。
MenuBuilder を使用した記法(推奨)
use tauri::menu::{MenuBuilder, SubmenuBuilder};
#[cfg_attr(mobile, tauri::mobile_entry_point)]
pub fn run() {
tauri::Builder::default()
.setup(|app| {
// 1. サブメニュー「ファイル」を作成
// text() メソッドで項目を追加できます
let file_menu = SubmenuBuilder::new(app, "ファイル")
.text("open", "開く")
.text("save", "保存")
.build()?;
// 2. アプリケーションメニューを作成し、サブメニューを追加
let menu = MenuBuilder::new(app)
.item(&file_menu)
.build()?;
// アプリ全体にセット
app.set_menu(menu)?;
Ok(())
})
.on_menu_event(|app, event| {
// メニューイベントのハンドリング
match event.id().0.as_str() {
"open" => {
println!("開くがクリックされました");
}
"save" => {
println!("保存がクリックされました");
}
_ => {}
}
})
.run(tauri::generate_context!())
.expect("error while running tauri application");
}
従来の記法(MenuItem を個別に作成)
use tauri::menu::{Menu, MenuItem, Submenu};
#[cfg_attr(mobile, tauri::mobile_entry_point)]
pub fn run() {
tauri::Builder::default()
.setup(|app| {
let handle = app.handle();
// 1. メニュー項目の作成
let open = MenuItem::with_id(handle, "open", "開く", true, None::<&str>)?;
let save = MenuItem::with_id(handle, "save", "保存", true, None::<&str>)?;
// 2. サブメニューの作成
let file_menu = Submenu::with_items(handle, "ファイル", true, &[&open, &save])?;
// 3. アプリケーションメニューの作成
let menu = Menu::with_items(handle, &[&file_menu])?;
// 4. アプリ全体にセット
app.set_menu(menu)?;
Ok(())
})
.on_menu_event(|app, event| {
match event.id().0.as_str() {
"open" => {
println!("開くがクリックされました");
}
"save" => {
println!("保存がクリックされました");
}
_ => {}
}
})
.run(tauri::generate_context!())
.expect("error while running tauri application");
}
補足
* Rustでの作成: 静的なメニューであれば、Rust側で作成する方が起動時のチラつきがなく、パフォーマンスが良い場合があります。
* Webviewごとの設定: setAsAppMenu() はアプリ全体に適用されますが、setAsWindowMenu() を使うと特定のウィンドウにのみメニューを設定できます (Windows/Linux)。
* macOSの注意: macOS ではグローバルメニューバーとして表示されるため、Menu には Submenu のみを追加できます。
* 初期化タイミング: macOS ではアプリ起動直後にメニューが必要です。React の useEffect や Vue の onMounted など、早い段階で実行してください。