自作のタイトルバーにメニューを組み込む

Recipe ID: menu-017

OS 標準のタイトルバーを非表示にし、HTML/CSS で独自のタイトルバーとメニューを作成する方法を解説します。
これにより、アプリケーションのデザインと完全に統合された UI を実現できます。

Tauri v2 では、decorations: false で標準タイトルバーを消し、JavaScript API でウィンドウ操作(最小化、最大化、閉じる)とメニュー表示を実装します。

前提条件

Permissions (権限) の設定

src-tauri/capabilities/default.json に以下の権限を追加します。

{
    "permissions": [
        ...,
        "core:window:allow-close",
        "core:window:allow-minimize",
        "core:window:allow-start-dragging",
        "core:window:allow-toggle-maximize",
        "core:menu:default"
    ]
}

1. 静的な設定 (tauri.conf.json)

標準のタイトルバーを消すために decorationsfalse にします。

{
  "app": {
    "windows": [
      {
        "decorations": false
      }
    ]
  }
}

2. フロントエンドで実装する (HTML / CSS / TypeScript)

data-tauri-drag-region 属性を付けた要素は、ウィンドウ移動のハンドルとして機能します。

HTML & CSS (簡易例)

<div class="titlebar">
  <div class="menubar">
    <button id="file-menu-btn">ファイル</button>
    <button id="edit-menu-btn">編集</button>
  </div>
  <div data-tauri-drag-region class="drag-region">
    マイアプリ
  </div>
  <div class="window-controls">
    <button id="minimize-btn">-</button>
    <button id="maximize-btn">□</button>
    <button id="close-btn">×</button>
  </div>
</div>

<style>
.titlebar {
  display: flex;
  background: #333;
  color: white;
  height: 30px;
  user-select: none;
}
.drag-region {
  flex-grow: 1;
  display: flex;
  align-items: center;
  justify-content: center;
}
button {
  background: none;
  border: none;
  color: white;
  padding: 0 10px;
  cursor: pointer;
}
button:hover { background: rgba(255,255,255,0.1); }
</style>

TypeScript

メニューボタンがクリックされたら、Tauri の Menu API を使用してネイティブメニューをポップアップさせます。

import { getCurrentWindow } from '@tauri-apps/api/window';
import { Menu } from '@tauri-apps/api/menu';

const appWindow = getCurrentWindow();

// --- ウィンドウ操作 ---
document.getElementById('minimize-btn')?.addEventListener('click', () => appWindow.minimize());
document.getElementById('maximize-btn')?.addEventListener('click', () => appWindow.toggleMaximize());
document.getElementById('close-btn')?.addEventListener('click', () => appWindow.close());

// --- メニュー操作 ---

// ファイルメニューの作成と表示
document.getElementById('file-menu-btn')?.addEventListener('click', async () => {
    const menu = await Menu.new({
        items: [
            { text: '新規作成', action: () => console.log('New') },
            { text: '開く', action: () => console.log('Open') },
            { item: 'Separator' },
            { text: '終了', action: () => appWindow.close() },
        ]
    });
    
    // カーソル位置 (あるいはボタンの下など指定座標) にポップアップ表示
    await menu.popup();
});

// 編集メニュー
document.getElementById('edit-menu-btn')?.addEventListener('click', async () => {
    const menu = await Menu.new({
        items: [
            { item: 'Undo' },
            { item: 'Redo' },
            { item: 'Separator' },
            { item: 'Cut' },
            { item: 'Copy' },
            { item: 'Paste' },
        ]
    });
    await menu.popup();
});

補足

* ネイティブ感: Menu.popup() は OS ネイティブのコンテキストメニューを表示するため、簡単かつ OS の機能(コピー&ペースト等)をそのまま利用できます。
* 完全カスタム: メニューの見た目も完全にカスタマイズしたい場合は、Menu API は使わず、通常の HTML/CSS/JavaScript でドロップダウンメニューを実装する必要があります。