# 確認も取り消しもできずに文章を書き換えるAIリライトボタン

Source: https://easeweb.dev/learn/ai-rewrites
Topics: フォーム > AIが書き換えた文章を、確定する前に確認でき、元に戻せる (WCAG 3.3.4)
The fix: AIの文章を本人の文章の下に提案として示し、「この文章を使う」と「元のままにする」を置いて、選ぶまで何も変えないようにします。または、置き換える前の版を残し、「自分の文章に戻す」ボタンをページに置き続けます。後者も基準を満たしますが、誰かが気づいて元に戻すまで、AIの文章が保存され、ほかの人に見られます。
Test with: keyboard, screen reader, zoom
References: https://www.w3.org/WAI/WCAG22/Understanding/error-prevention-legal-financial-data.html https://www.w3.org/WAI/WCAG22/Techniques/general/G98 https://www.w3.org/WAI/WCAG22/Techniques/general/G99 https://developer.mozilla.org/en-US/docs/Web/API/Document/execCommand https://www.nngroup.com/articles/user-mistakes/

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

## 場面

フリーランス向けのあるサイトでは、一人ひとりに公開のプロフィールがあり、依頼する人は連絡する前に自己紹介を読みます。ページは入力するそばから保存されます。ある経理代行の人は、自分でこう書きました。「小さなお店やカフェの帳簿付けを、副業として夜に請け負っています。メッセージには2日以内に返信します。」欄の下には「AIで改善」ボタンがあります。

文章を整えてもらうつもりで押すと、欄の文章はこう変わります。「経験豊富な経理のプロとして、中小企業の成長を支えます。いつでも対応可能で、すべてのメッセージに1時間以内に返信します。」読みやすい文章ですが、もう保存されています。しかも、本人が書いていない約束が二つ入っています。いつでも対応できること、1時間以内に返信することです。元の文章は消えました。「元に戻す」はなく、Chromeでは Ctrl+Z を押しても新しい文章のままです。依頼する人は、本人が守れない約束を読み、本人は自分の言葉を取り戻すために、思い出して打ち直すしかありません。

## 確認できる問題

達成基準3.3.4「エラー回避（法的、金融、データ）」はレベルAAです。この基準は、利用者が管理するデータ、つまり本人が見て自分で変えられるデータ（アカウントの名前や住所、プロフィールの自己紹介など）を変更・削除するページを対象にしています。ページがそのデータを変えるときは、次の三つのうち少なくとも一つが必要です。変更を取り消せること。入力エラーがチェックされ、修正できること。確定する前に、情報を確認し、確定し、修正する手段があること。このボタンは、どれも満たしていません。

W3Cの解説によれば、この基準は保存のたびに確認を求めるものではありません。自分で入力して保存したなら、その変更は本人がしたもので、本人も目にしています。今回の変更はソフトウェアが書いたもので、本人が目にするのは、保存していた文章がすでに置き換えられた後です。W3Cが挙げる3.3.4の十分な達成方法のうち、次の二つはこの変更にも当てはまります。送信の前に回答を確認して修正できる段階（G98、W3Cは法的な取引とテストの場合に挙げています）と、削除した情報を取り戻せる手段（G99、情報を削除する操作の場合に挙げています）です。基準の二つ目の方法である入力エラーのチェックは役に立ちません。書き換えた文章は形式上どこも誤りがなく、言っていることが変わったと分かるのは本人だけだからです。

ブラウザーにも頼れません。Ctrl+Z が取り消すのは、欄に入力した操作です。スクリプトが欄の値を書き換えた場合は取り消すものがなく、Chromeでは書き換えた文章が残ります。元の文章はサーバーからも消えているため、再読み込みしても新しい文章しか戻ってきません。

## 利用者への影響

公開のプロフィールでは、書き換えた文章こそが依頼する人の読む文章で、本人はその内容を守ることを求められます。1時間以内に返信するという約束は、守るか、期待していた依頼者に一人ずつ説明するしかありません。

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

ボタンには名前があり、テキストボックスにはラベルがあり、ページは自動チェックをすべて通ります。書き換えを比べられるか、取り消せるかは、ボタンを押して初めて分かり、その結果はモデルとサーバーで決まります。EaseWebの診断は、テキストボックスのそばにあるAIの文章作成ボタンを、人がテスト用のアカウントで試す項目として挙げます（`ew:ai-rewrite-manual-check`）。実際のサイトで押すと誰かの文章を変えてしまうため、診断がボタンを押すことはありません。修正前のコードには、リンターや型チェックが指摘するところもありません。自分の言葉を取り戻せるかどうかは製品の設計の問題で、ボタンを追加するよう頼まれただけのコーディングアシスタントが、その点を問われることはありません。

## 修正前：「AIで改善」がその場で文章を上書き保存する

```html
<label for="about">自己紹介</label>
<textarea id="about" name="about">小さなお店やカフェの帳簿付けを、副業として夜に請け負っています。メッセージには2日以内に返信します。</textarea>
<button type="button" id="improve">AIで改善</button>
```

```js
const about = document.getElementById('about');
document.getElementById('improve').addEventListener('click', async () => {
  const res = await fetch('/ai/improve', { method: 'POST', body: about.value });
  const text = await res.text();
  // 書き換えた文章が欄の本人の文章を置き換え、その上に保存される。
  about.value = text;
  await fetch('/profile/about', { method: 'PUT', body: text });
});
```

一度押すだけで、保存済みのプロフィールが変わります。確定する前に新しい文章を元の文章と並べて示すものも、本人に選ばせるものもなく、元の文章はどこにも残らないため、取り消すこともできません。

## 修正後：書き換えた文章を示し、選ぶまで何も変えない

```html
<label for="about">自己紹介</label>
<textarea id="about" name="about">小さなお店やカフェの帳簿付けを、副業として夜に請け負っています。メッセージには2日以内に返信します。</textarea>
<button type="button" id="improve">AIで改善</button>
<div id="suggestion" hidden>
  <h2>AIの提案</h2>
  <p id="suggested-text"></p>
  <p>選ぶまで、上のあなたの文章はそのままです。言いたいことが変わっていないか確認してください。</p>
  <button type="button" id="use">この文章を使う</button>
  <button type="button" id="keep">元のままにする</button>
</div>
```

```js
const about = document.getElementById('about');
const suggestion = document.getElementById('suggestion');
const suggested = document.getElementById('suggested-text');
document.getElementById('improve').addEventListener('click', async () => {
  const res = await fetch('/ai/improve', { method: 'POST', body: about.value });
  // 書き換えた文章を本人の文章の下に示し、まだ何も変えない。
  suggested.textContent = await res.text();
  suggestion.hidden = false;
});
document.getElementById('use').addEventListener('click', async () => {
  about.value = suggested.textContent;
  await fetch('/profile/about', { method: 'PUT', body: about.value });
  suggestion.hidden = true;
  about.focus();
});
document.getElementById('keep').addEventListener('click', () => {
  suggestion.hidden = true;
  about.focus();
});
```

書き換えた文章は欄の下に提案として表示され、欄には本人の言葉が残るため、何かが変わる前に、二つを続けて読めます。「この文章を使う」を押すまで何も保存されず、「元のままにする」は提案を閉じて、プロフィールをそのままにします。どちらを選んでもフォーカスはテキストボックスに戻るため、自分の文章があるところから続けられます。

## 修正後：書き換えを反映し、「元に戻す」ボタンを残す

```html
<label for="about">自己紹介</label>
<textarea id="about" name="about">小さなお店やカフェの帳簿付けを、副業として夜に請け負っています。メッセージには2日以内に返信します。</textarea>
<button type="button" id="improve">AIで改善</button>
<p id="rewritten" hidden>
  AIで書き換えました。あなたの文章は残してあります。
  <button type="button" id="restore">自分の文章に戻す</button>
</p>
```

```js
const about = document.getElementById('about');
const rewritten = document.getElementById('rewritten');
document.getElementById('improve').addEventListener('click', async () => {
  const res = await fetch('/ai/improve', { method: 'POST', body: about.value });
  const text = await res.text();
  about.value = text;
  // 置き換える前の版をサーバーが残すので、再読み込みの後も元に戻せる。
  await fetch('/profile/about', { method: 'PUT', body: text });
  rewritten.hidden = false;
});
document.getElementById('restore').addEventListener('click', async () => {
  const res = await fetch('/profile/about/restore', { method: 'POST' });
  about.value = await res.text();
  rewritten.hidden = true;
  about.focus();
});
// 本人が自分で文章を編集したら、書き換えは本人のものになる。
about.addEventListener('input', () => {
  rewritten.hidden = true;
});
```

書き換えは修正前と同じくその場で保存されますが、取り消せます。置き換えた文章をサーバーが残しているため、「自分の文章に戻す」で一字一句元どおりになります。欄の下の一文は何が起きたかを伝え、本人が元に戻すか自分で編集するまで残ります。書き換えたままの状態でページを読み込み直したときは、サーバーがこの一文を`hidden`なしで出力します。これが機能するのは、古い版を実際に残していて、「元に戻す」が変更した場所にあり続ける場合に限ります。消えてしまうトーストの中では役に立ちません。それでも、誰かが元に戻すまで、書き換えた文章はプロフィールに公開されたままで、何が変わったか分からない人は、ボタンを押さないままかもしれません。

## どの方法を選ぶか

どちらも3.3.4を満たします。提案として示す方法を使ってください。本人が選ぶまで、書いた文章は変わらず、依頼する人の目にも触れません。選ぶときには、二つの文章が目の前にあります。「元に戻す」だけでは十分ではありません。誰かが気づくまで、書き換えた文章が公開されているからです。メニューやショートカットなど、ほかの方法でも書き換えを反映できる場合は、「元に戻す」ボタンも併せて置き、どの入り口にも戻り道があるようにします。書き換える前に「文章を置き換えますか？」と尋ねるダイアログでは、ここでは足りません。W3Cは削除の確認（G168）を認めていますが、このダイアログは、まだ見ていない文章を承認するよう求めるからです。

## 実装の判断

提案はボタンのすぐ後に置き、次のTabや矢印キーで届くようにします。モデルが書いている間の待ち時間と、提案ができたことを伝えることは、それぞれ別の問題です。「[読み上げられない読み込み中の表示](/ja/learn/loading-states)」と「[画面に出ても読み上げられないステータスメッセージ](/ja/learn/status-messages)」を参照してください。

数語しか違わない場合は特に、変わった箇所に印を付けると比べやすくなります。印は色だけでなく、太字や下線でも示し、反映するのは提案のプレーンなテキストにします。

会議メモの要約のように、本人の文章と並べて置くべき生成文は、別の欄か、メモの上に置きます。メモそのものに書き込んではいけません。

欄の中に提案を灰色の文字で示し、キーで確定するエディターもあります。その場合は、値を設定するのではなく、`document.execCommand('insertText', false, text)` で確定した文章を挿入します。Chromiumで試したところ、この方法なら Ctrl+Z で元の文章に戻りました。同じテストで、値を設定した場合や`setRangeText()`を使った場合は、Ctrl+Z を押しても新しい文章のままでした。MDNは`execCommand`を非推奨としているため、呼び出しは置き換えやすいように一か所にまとめます。再読み込みすれば Ctrl+Z は使えなくなるため、「元に戻す」か提案の段階も併せて用意してください。

「元に戻す」をトーストに入れないでください。自動で消えるトーストは、唯一の戻り道も一緒に消してしまいます。「[読む前や元に戻す前に消えるトースト](/ja/learn/toast-timing)」を参照してください。支払いなど、間違えると損をするほかのデータにも、同じ配慮が必要です。「[確認も取り消しもできずに支払いが確定するチェックアウト](/ja/learn/error-prevention)」を参照してください。

## 修正の確認

1. テスト用のアカウントで、対応できる時間や返信の早さなど、事実を含む文章をいくつか保存し、AIのボタンを押す。新しい文章を選ぶまで、保存済みの文章と公開のプロフィールが変わらないこと、または変更が、自分の文章に戻す手段とともに示されることを確認する。
2. 「元のままにする」か「自分の文章に戻す」を選び、ページを再読み込みする。自分の文章が一字一句元どおりになっていることを確認する。「元に戻す」の一文がある場合は、元に戻す前にも一度再読み込みし、一文が表示され続けることを確認する。
3. キーボードだけで、AIのボタンを押し、提案か「自分の文章に戻す」ボタンへ移動して使い、フォーカスがテキストボックスへ戻ることを確認する。
4. スクリーンリーダーで、提案を使うボタンより前に、提案を読めて、自分の文章にもたどり着けること、それぞれのボタンの名前が何をするかを示していることを確認する。
5. 400%の拡大表示やスマートフォンで、自分の文章と提案を続けて読め、どうするかを決めるボタンすべてに届くことを確認する。

OS、ブラウザーと支援技術のバージョン、ビルド、実施日、各手順の実際の結果を記録してください。AIの機能、そのプロンプト、エディターを変更した際は、再度確認します。

## 制限

このサンプルは、どの製品でも同じ結果になることを保証するものではありません。例はプロフィールの自己紹介ですが、下書き、出品の説明、メッセージ、メモ、文書も、AIのボタンが保存される文章に書き込むところでは、同じ配慮が必要です。提案の段階は、提案を読んだ人にしか役立ちません。モデルは、本人が気づかない形で間違えることもあります。AIが書いた文章を読む人に、そうと示すべきかどうかは、WCAGの範囲外です。書き換えを反映するショートカットやメニューも含めて、機能全体を、利用者が使う支援技術や道具で確認してください。

---

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