# キーボードで入れず、開いても何も伝えない操作メニュー

Source: https://easeweb.dev/learn/menu-button
Topics: 複雑なウィジェット > 操作メニューのボタンがメニューを開くことを伝え、フォーカスをメニューに移す (WCAG 2.1.1, 4.1.2)
The fix: メニューボタンのパターンどおりに作るか、開閉ボタンにします。メニューボタンなら、aria-haspopup="menu" と aria-expanded のあるボタン、メニュー項目を並べた role="menu"、開いたときに最初の項目へフォーカスを移す処理、下矢印キー、上矢印キー、Home、End、Escapeの操作をそろえます。開閉ボタンなら、aria-expanded のあるボタンのすぐ後ろに普通のボタンのリストを表示し、その中をTabで移動できるようにします。
Test with: keyboard, screen reader, forced colors, zoom
References: https://www.w3.org/WAI/ARIA/apg/patterns/menu-button/ https://www.w3.org/WAI/ARIA/apg/patterns/menu-button/examples/menu-button-actions/ https://www.w3.org/WAI/ARIA/apg/patterns/menubar/ https://www.w3.org/WAI/ARIA/apg/patterns/disclosure/ https://www.w3.org/WAI/WCAG22/Understanding/keyboard.html https://www.w3.org/WAI/WCAG22/Understanding/name-role-value.html https://www.w3.org/WAI/WCAG22/Techniques/failures/F59 https://www.w3.org/WAI/WCAG22/Techniques/failures/F15 https://www.w3.org/TR/wai-aria-1.2/#menu https://inclusive-components.design/menus-menu-buttons/

よくある問題を再現した学習用のサンプルです。実在のクライアントの診断結果ではありません。コードは出発点となる実装例のため、実際の製品でも確認してください。ここでは支援技術でのテスト結果は報告していません。

## 場面

あるショップの注文履歴では、注文ごとにカードが並び、それぞれに「詳細」ボタンがあります。押すと、「もう一度購入」「返品する」「領収書をダウンロード」「問題を報告」という、その注文でできる4つの操作が下に開きます。「詳細」をクリックするとボタンの下にメニューが開き、「領収書をダウンロード」をクリックすると領収書がダウンロードされます。ボタンは本物のbuttonなので、Tabキーで届き、Enterキーでメニューが開きます。ところがフォーカスは「詳細」に残ったままで、各操作はクリック処理を付けたdivです。次にTabキーを押すと、開いたメニューを飛ばして、カードの下の「すべての注文を見る」へ移ります。下矢印キーはページをスクロールするだけです。メニューの中には、マウスなしでは何も届きません。スクリーンリーダーは「詳細、ボタン」と読み、Enterキーを押しても新しく何も読まれません。ボタンがメニューを開くことも、メニューが開いたことも伝わりません。スクリーンリーダー自身のキーで読み進めると、4つの操作はただの文字として出てきます。押せるものなのか、どのボタンのものなのかを示す役割はありません。

そこでチームは、手っ取り早くメニューに仕立てます。ボタンに `aria-haspopup="menu"`、パネルに `role="menu"`、各操作に `role="menuitem"` を付け、それ以外は何もしません。スクリーンリーダーはボタンがメニューを開くと伝えるようになりますが、押した後は何も変わりません。フォーカスはボタンに残り、メニューが開いたことは伝わらず、Tabキーは今もすべての項目を飛ばし、メニューが約束する矢印キーは何もしません。

## 確認できる問題

達成基準2.1.1「キーボード」は、マウスでできることはすべてキーボードでもできることを求めています。マウスはdivをクリックして操作を実行しますが、divはフォーカスを受けないため、キーボードではメニューを開けても中の何にも届きません。「領収書をダウンロード」を含め、メニューのどの操作にもマウスが必要です。メニューのロールを足しても、この点は何も変わりません。ロールは要素が何であるかを伝えるもので、どう動くかは変えません。項目は今もフォーカスを受けず、矢印キーに応えるスクリプトもありません。

達成基準4.1.2「名前（name）・役割（role）及び値（value）」は、コントロールの役割と状態が支援技術に伝わり、その変化も伝わることを求めています。ボタンの名前と役割は伝わっていますが、メニューを開くことも、メニューが開いているかどうかも伝わっていないため、押しても、スクリーンリーダーが読み上げられる変化が何も起きません。各操作には役割がまったくありません。divにクリック処理を付けても、アクセシビリティAPIに役割は伝わらず、これは失敗例F59にあたります。ロールを足すと、ボタンはメニューを開くことを伝えますが、開いているかどうかは今も伝えず、フォーカスもボタンに残るため、メニューが開いても何も聞こえないままです。ロールが約束する動きのないロールは、アクセシビリティAPIの使い方が不完全なカスタムのコントロールとして、失敗例F15にあたります。

## 利用者への影響

操作メニューは、注文履歴、住所録、ファイルの一覧、チームの設定、コメントなどにあり、行ごとに1つずつ置かれることもよくあります。スマートフォンでは、画面に並べきれない操作を同じボタンにまとめることも多くあります。その奥にあるものは、クリックできない人には届かず、画面を見られない人には開いたことさえ分かりません。

## 自動チェックとAIの限界

最初のメニューには名前のある本物のbuttonと、役割のないdivしかないため、axeが報告することはありません。メニューのロールもaxeに合格します。どの `menuitem` も `menu` の中にあり、どれにも名前があるからです。axeが確かめるのはロールの組み合わせが正しいかで、フォーカスが項目に届くかや、キーが何をするかは確かめません。

この診断ツールはキーを押します。`aria-haspopup` でメニューを開くと伝えるボタンと、「More」「Actions」「Options」「詳細」「その他」「その他の操作」「操作」という名前のボタンや、kebab、overflow、dropdownなどのクラスを持つボタンを、サイトのナビゲーションとヘッダーの外から探します。それぞれを読み込み直したページでEnterキーを押して開き、現れたものを調べます。フォーカスがメニューに移らず、下矢印キーでもTabキーでも届かず、どの操作もTabの移動先でなければ、報告します。フォーカスを受けても、矢印キーでもHomeやEndでも、フォーカスが届いた項目から動けない `role="menu"` も報告します。メニューが開いてもフォーカスを自分に残し、`aria-expanded` のないボタンも報告し、`aria-expanded` がfalseのまま変わらないものも報告します。項目がTabの移動先で、矢印キーが何もしないメニューは、人が確認する項目として渡します。ほかの名前で、それと分かる属性やクラスのないメニューボタンや、ヘッダーの中のものは見つからず、並んでいる操作が利用者に必要なものかは、どの確認でも分かりません。

2つ目のメニューは、AIに直させるとこうなることがある形です。今あるdivにロールを足しただけで終わり、それでもaxeには合格します。すべての項目に `tabindex="0"` を付ける修正もあります。項目はそれぞれTabの移動先になりますが、矢印キーは何もしないメニューのままです。

## 修正前：ボタンと、クリックできるdivのドロップダウン

```html
<article class="order">
  <h2>注文1042</h2>
  <p>10月14日にお届け済み</p>
  <div class="actions">
    <button type="button" class="actions-button">詳細</button>
    <div class="actions-menu" hidden>
      <div class="item" data-action="buy-again">もう一度購入</div>
      <div class="item" data-action="return">返品する</div>
      <div class="item" data-action="invoice">領収書をダウンロード</div>
      <div class="item" data-action="report">問題を報告</div>
    </div>
  </div>
</article>
```

```css
.actions { position: relative; }
.actions-menu { position: absolute; top: 100%; left: 0; min-width: 12rem; padding: 0.25rem; background: #fff; border: 1px solid #d4d4d8; border-radius: 0.5rem; }
.actions-menu .item { padding: 0.5rem 0.75rem; border-radius: 0.375rem; cursor: pointer; }
.actions-menu .item:hover { background: #f4f4f5; }
```

```js
const button = document.querySelector('.actions-button');
const menu = document.querySelector('.actions-menu');
button.addEventListener('click', () => {
  menu.hidden = !menu.hidden;
});
menu.addEventListener('click', (event) => {
  const item = event.target.closest('[data-action]');
  if (!item) return;
  menu.hidden = true;
  runAction(item.dataset.action);
});
```

ボタンはメニューを開きますが、フォーカスを中へ移す処理はなく、各操作は `click` にしか応えずフォーカスも受けないため、キーボードはボタンで止まります。ボタンが何かを開くことも、開いているかどうかも、その下の文字が操作であることも、マークアップのどこにも書かれていません。

## 修正前：同じdivにメニューのロールを足しただけ

```html
<article class="order">
  <h2>注文1042</h2>
  <p>10月14日にお届け済み</p>
  <div class="actions">
    <button type="button" class="actions-button" aria-haspopup="menu">詳細</button>
    <div class="actions-menu" role="menu" hidden>
      <div class="item" role="menuitem" data-action="buy-again">もう一度購入</div>
      <div class="item" role="menuitem" data-action="return">返品する</div>
      <div class="item" role="menuitem" data-action="invoice">領収書をダウンロード</div>
      <div class="item" role="menuitem" data-action="report">問題を報告</div>
    </div>
  </div>
</article>
```

```css
.actions { position: relative; }
.actions-menu { position: absolute; top: 100%; left: 0; min-width: 12rem; padding: 0.25rem; background: #fff; border: 1px solid #d4d4d8; border-radius: 0.5rem; }
.actions-menu .item { padding: 0.5rem 0.75rem; border-radius: 0.375rem; cursor: pointer; }
.actions-menu .item:hover { background: #f4f4f5; }
```

```js
const button = document.querySelector('.actions-button');
const menu = document.querySelector('.actions-menu');
button.addEventListener('click', () => {
  menu.hidden = !menu.hidden;
});
menu.addEventListener('click', (event) => {
  const item = event.target.closest('[data-action]');
  if (!item) return;
  menu.hidden = true;
  runAction(item.dataset.action);
});
```

CSSとスクリプトは変わらず、違いは3つの属性だけです。この3つの属性は、メニューの中へ移るフォーカス、矢印キーでの移動、開いている状態という、メニューボタンとしての動きを約束しますが、そのどれも実装されていません。ボタンはメニューを開くと伝えるようになりましたが、押してもフォーカスはボタンから動かず、メニューが開いたことを伝える `aria-expanded` もありません。項目は役割を持っても今もフォーカスを受けないため、Tabキーでも矢印キーでも届きません。axeはこれを合格にします。

## 修正後：メニューボタン

```html
<article class="order">
  <h2>注文1042</h2>
  <p>10月14日にお届け済み</p>
  <div class="actions">
    <button type="button" class="actions-button" id="order-1042-actions" aria-haspopup="menu" aria-expanded="false" aria-controls="order-1042-menu">詳細</button>
    <div class="actions-menu" id="order-1042-menu" role="menu" aria-labelledby="order-1042-actions" hidden>
      <button type="button" role="menuitem" tabindex="-1" data-action="buy-again">もう一度購入</button>
      <button type="button" role="menuitem" tabindex="-1" data-action="return">返品する</button>
      <button type="button" role="menuitem" tabindex="-1" data-action="invoice">領収書をダウンロード</button>
      <button type="button" role="menuitem" tabindex="-1" data-action="report">問題を報告</button>
    </div>
  </div>
</article>
```

```css
.actions { position: relative; }
.actions-menu { position: absolute; top: 100%; left: 0; min-width: 12rem; padding: 0.25rem; background: #fff; border: 1px solid #d4d4d8; border-radius: 0.5rem; }
.actions-menu [role='menuitem'] { display: block; width: 100%; padding: 0.5rem 0.75rem; border: 0; border-radius: 0.375rem; background: none; font: inherit; text-align: left; cursor: pointer; }
.actions-menu [role='menuitem']:is(:hover, :focus) { background: #f4f4f5; }
.actions-menu [role='menuitem']:focus-visible { outline: 2px solid #2563eb; outline-offset: -2px; }
```

```js
const actions = document.querySelector('.actions');
const button = actions.querySelector('.actions-button');
const menu = document.getElementById(button.getAttribute('aria-controls'));
const items = [...menu.querySelectorAll('[role="menuitem"]')];
function setOpen(open) {
  menu.hidden = !open;
  button.setAttribute('aria-expanded', String(open));
}
// Enter、Space、クリックでメニューを開き、最初の操作へフォーカスを移す。
button.addEventListener('click', () => {
  setOpen(menu.hidden);
  if (!menu.hidden) items[0].focus();
});
// 下と上で操作の間を移動し、端では反対側へ回る。HomeとEndで端へ移動する。
// Escapeでメニューを閉じ、ボタンへ戻る。
menu.addEventListener('keydown', (event) => {
  const at = items.indexOf(document.activeElement);
  const to = { ArrowDown: at + 1, ArrowUp: at - 1, Home: 0, End: items.length - 1 }[event.key];
  if (to !== undefined) {
    event.preventDefault();
    items[(to + items.length) % items.length].focus();
  } else if (event.key === 'Escape') {
    setOpen(false);
    button.focus();
  }
});
menu.addEventListener('click', (event) => {
  const item = event.target.closest('[data-action]');
  if (!item) return;
  setOpen(false);
  button.focus();
  runAction(item.dataset.action);
});
// Tabでメニューを出たときなど、ほかの場所へのフォーカスやクリックで閉じる。
for (const type of ['focusin', 'click']) {
  document.addEventListener(type, (event) => {
    if (!actions.contains(event.target)) setOpen(false);
  });
}
```

ARIA Authoring Practicesのメニューボタンのパターンです。`aria-haspopup="menu"` で、スクリーンリーダーはボタンがメニューを開くことを伝え、`aria-expanded` で開いているかどうかを伝えます。Enterキー、Spaceキー、クリックでメニューが開き、フォーカスが「もう一度購入」へ移るため、スクリーンリーダーはボタンの名前が付いたメニューと、その項目を読み上げます。多くの場合、「4項目中1」のような位置も読まれます。項目はbuttonなので、キーの処理を書かなくてもEnterキーとSpaceキーで実行でき、`role="menuitem"` でメニューの項目としての役割を持ちます。`tabindex="-1"` で項目をTabの移動先から外し、スクリプトで項目の間のフォーカスを動かします。下矢印キーと上矢印キーで移動し、端では反対側へ回り、HomeとEndで最初と最後へ移ります。Escapeキーを押すか操作を実行すると、メニューが閉じてフォーカスが「詳細」に戻ります。Tabキーを押すとメニューを出てページの次の部品へ進み、メニューは閉じます。

## 修正後：普通のボタンを並べた開閉ボタン

```html
<article class="order">
  <h2>注文1042</h2>
  <p>10月14日にお届け済み</p>
  <div class="actions">
    <button type="button" class="actions-button" aria-expanded="false" aria-controls="order-1042-menu">詳細</button>
    <ul class="actions-menu" id="order-1042-menu" hidden>
      <li>
        <button type="button" data-action="buy-again">もう一度購入</button>
      </li>
      <li>
        <button type="button" data-action="return">返品する</button>
      </li>
      <li>
        <button type="button" data-action="invoice">領収書をダウンロード</button>
      </li>
      <li>
        <button type="button" data-action="report">問題を報告</button>
      </li>
    </ul>
  </div>
</article>
```

```css
.actions { position: relative; }
.actions-menu { position: absolute; top: 100%; left: 0; min-width: 12rem; margin: 0; padding: 0.25rem; list-style: none; background: #fff; border: 1px solid #d4d4d8; border-radius: 0.5rem; }
.actions-menu button { display: block; width: 100%; padding: 0.5rem 0.75rem; border: 0; border-radius: 0.375rem; background: none; font: inherit; text-align: left; cursor: pointer; }
.actions-menu button:is(:hover, :focus) { background: #f4f4f5; }
.actions-menu button:focus-visible { outline: 2px solid #2563eb; outline-offset: -2px; }
```

```js
const actions = document.querySelector('.actions');
const button = actions.querySelector('.actions-button');
const menu = document.getElementById(button.getAttribute('aria-controls'));
function setOpen(open) {
  menu.hidden = !open;
  button.setAttribute('aria-expanded', String(open));
}
// リストはページ上でボタンの直後にあるため、次のTabで中へ入る。
button.addEventListener('click', () => setOpen(menu.hidden));
menu.addEventListener('click', (event) => {
  const item = event.target.closest('[data-action]');
  if (!item) return;
  setOpen(false);
  button.focus();
  runAction(item.dataset.action);
});
// Escapeでリストを閉じ、ボタンへ戻る。
actions.addEventListener('keydown', (event) => {
  if (event.key === 'Escape' && !menu.hidden) {
    setOpen(false);
    button.focus();
  }
});
// ほかの場所へのフォーカスやクリックで閉じる。
for (const type of ['focusin', 'click']) {
  document.addEventListener(type, (event) => {
    if (!actions.contains(event.target)) setOpen(false);
  });
}
```

メニューのロールをやめ、各操作をリストに並べた普通のボタンにしています。`aria-expanded` があるので、スクリーンリーダーは「詳細、ボタン、折りたたみ」のように読み、押すと「展開」と読みます。フォーカスは「詳細」に残りますが、リストがページ上でそのすぐ後ろにあるため、次のTabキーで「もう一度購入」へ移ります。中へ入るときに4項目のリストだと伝えるスクリーンリーダーもあります。各操作はTabの移動先で、EnterキーかSpaceキーで実行でき、最後の操作の後でTabキーを押すと、リストを閉じてページの先へ進みます。これが成り立つのは、マークアップ上でリストがボタンの直後にある間だけです。ページの末尾に描かれたリストには、最後にしか届きません。

## どの方法を選ぶか

どちらも基準を満たします。小さな変更で済むのは開閉ボタンで、この例のように、サイトのページにある少数の操作に向いています。操作は、どのブラウザーもスクリーンリーダーも音声操作のソフトもすでに知っているボタンで、属性1つと開閉の処理だけで作れ、ページのほかの部分と同じようにTabキーで移動できます。メニューボタンは、メールソフト、ファイル管理、エディターのように、アプリケーションとして動くページで作ります。操作がOSのメニューと同じように動くことが期待され、操作をすべてTabの移動先にすると、どの行も通り過ぎるのに時間がかかる場面です。その場合は、ロール、開いている状態、中へ移るフォーカス、すべてのキーと、全部が必要です。手本は、ARIA Authoring PracticesのActionsメニューの例です。カードに余裕があれば、操作を隠さないことも考えてください。[右クリックや長押し、スワイプでしか出ない操作メニュー](/ja/learn/context-menus)で示しているように、操作ごとにボタンを置く方法です。

## 実装の判断

注文の一覧では、どのカードのボタンも「詳細」です。ボタンの文字はそのままにして、どの注文のものかを加えます。カードの見出しを `aria-describedby` で指すか、文字の後ろに隠したテキストを足し（`詳細<span class="visually-hidden">（注文1042）</span>`）、名前が画面に見える文字で始まるようにします。[表示と名前が食い違うボタンとリンク](/ja/learn/label-in-name)で説明しているとおりです。メニューは、`aria-labelledby` でボタンから名前を得ます。

メニューボタンのパターンでは、ほかにもできることがあります。ボタンで下矢印キーを押すとメニューを開いて最初の項目へ、上矢印キーなら最後の項目へ移る動きも認められています。文字を押すと、その文字で始まる次の項目へ移る方法もあり、長いメニューで役立ちます。今は使えない操作は、`aria-disabled="true"` を付けてメニューに残します。そうすれば、その操作があることが伝わり、矢印キーでも届きます。オンとオフを切り替える操作は、`aria-checked` を付けた `menuitemcheckbox` にします。操作メニューにサブメニューは入れないでください。サブメニューごとに、開く右矢印キーと出る左矢印キー、画面上の配置と、正しく作るべきものが増えます。

`role="menu"` に入れるのはメニュー項目だけで、リンク、入力欄、見出しを並べることはできません。それらが必要なら、開閉ボタンかダイアログにします。「領収書を見る」のようにほかのページへのリンクは、開閉ボタンのリストならリンクのまま置けますが、メニューの中では `role="menuitem"` も必要です。

どちらのメニューも、`popover` 属性で作れます。その場合、ブラウザーがEscapeキーとメニュー外のクリックで閉じ、Escapeキーで閉じたときはフォーカスをボタンに戻し、ページの上に描くため、カードの `overflow: hidden` で切れることもありません。[右クリックや長押し、スワイプでしか出ない操作メニュー](/ja/learn/context-menus)のメニューは、この方法で作っています。ポップオーバーは、CSSのアンカー配置か数行のスクリプトで位置を決めるまでは、画面の中央に表示されます。使わない場合は、カードがメニューを切らないかを確かめます。一部の部品ライブラリーのように、メニューをページの末尾に描く場合、スクリプトで中へ移すフォーカスはそれでも届きますが、開閉ボタンのリストにはほかのすべての後でしか届きません。[フォーカス順の最後に回る、フローティングボタンとパネル](/ja/learn/floating-order)で説明しています。どちらも閉じたときにフォーカスがどこへ行くかは、[Tabで閉じてフォーカスを見失う検索パネル](/ja/learn/panel-dismissal)で扱っています。

ライブラリーのメニューの部品はさまざまです。フォーカスを移してすべてのキーを扱うものもあれば、ロールを付けるだけのものもあります。使う前に、キーボードで確かめてください。

## 修正の確認

1. マウスを使わずに、Tabで「詳細」へ移る。Enterキーで開き、Spaceキーでも開く。すべての操作にたどり着き、「領収書をダウンロード」を実行して、フォーカスが「詳細」に戻ることを確かめる。開閉ボタンでは、「詳細」の次のTabで「もう一度購入」へ移る。
2. スクリーンリーダーで「詳細」へ移る。ボタンがメニューを開くこと、または折りたたまれていることが読まれる。開閉して、読まれる状態がメニューと一致することを確かめる。
3. スクリーンリーダーでメニューを開く。メニューボタンでは、フォーカスが中へ移るときにメニューと最初の項目が、多くの場合「4項目中1」のような位置とともに読まれる。開閉ボタンでは、ボタンが展開と読まれ、次のTabで最初のボタンが読まれる（スクリーンリーダーによってはリストも読まれる）。
4. メニューボタンでは、すべてのキーをパターンと照らし合わせる。下矢印キーと上矢印キーで移動して端で反対側へ回り、HomeとEndで最初と最後の操作へ移り、Escapeキーでメニューが閉じて「詳細」へ戻り、Tabキーでメニューが閉じて先へ進む。どの項目も、それ自体はTabの移動先ではない。
5. 強制配色（Windowsのコントラスト テーマ）をオンにし、200%に拡大する。メニューの縁、フォーカスのある操作、フォーカスの枠がすべて見え、カードやウィンドウで切れている操作がない。

OS、ブラウザーと支援技術のバージョン、ビルド、実施日、各手順の実際の結果を記録してください。メニュー、その部品、ライブラリーを変更した際は、再度確認します。

## 制限

このサンプルは、どのアプリケーションでも同じ結果になることを保証するものではありません。スクリプトは最小限の例で、ページにメニューが1つだけの場合を想定し、先頭文字での移動、使えない項目、サブメニューはありません。サイト上部に並ぶリンクのドロップダウンはナビゲーションで、別のパターンです。[マウスでしか開かないか、開閉が伝わらないドロップダウンメニュー](/ja/learn/nav-menus)で扱っています。サイズのように値を選ぶドロップダウンはセレクトで、[キーボードで開けず、読み上げられないカスタムのドロップダウン](/ja/learn/custom-select)で扱っています。右クリックや長押しでしか開かないメニューは[右クリックや長押し、スワイプでしか出ない操作メニュー](/ja/learn/context-menus)で扱っています。3つの点のようにアイコンだけのボタンには名前も必要で、[名前がないアイコンだけのボタン](/ja/learn/icon-buttons)で説明しています。対象とする支援技術で、一連の操作全体をテストしてください。

## スクリーンリーダーでの動き（EaseWebが実機で確認）

`aria-expanded`: ボタンが開くメニューやセクションが、開いているかどうかを示します。

| スクリーンリーダー | ブラウザーとOS | 押す | Tabで移動 |
| --- | --- | --- | --- |
| NVDA | Chrome, Windows 11 | 未確認 | 未確認 |
| JAWS | Chrome, Windows 11 | 未確認 | 未確認 |
| VoiceOver | Safari, iOS | 未確認 | 未確認 |
| TalkBack | Chrome, Android | 未確認 | 未確認 |

`aria-haspopup="menu"`: ボタンがメニューを開くことを示します。ARIAでは、listbox、tree、grid、dialogも指定できます。

| スクリーンリーダー | ブラウザーとOS | Tabで移動 |
| --- | --- | --- |
| NVDA | Chrome, Windows 11 | 未確認 |
| JAWS | Chrome, Windows 11 | 未確認 |
| VoiceOver | Safari, iOS | 未確認 |
| TalkBack | Chrome, Android | 未確認 |

https://easeweb.dev/ja/learn/screen-reader-support

---

このガイドをコーディングエージェントで使う: MCP https://easeweb.dev/mcp（設定は https://easeweb.dev/ja/services/developers）
