UIXHERO

AI Chat UI(AIチャットUI)

AIアシスタントとの対話インターフェース。メッセージバブル・ストリーミング表示・ロール別スタイリング・入力欄・スケルトンローディング・エラー状態の設計パターンを解説する。

2026年3月3日
更新: 2026年9月14日
約18分
by Dengen Yosho(DGYS)

AIアシスタント(LLM)とユーザーが対話するためのインターフェース。メッセージバブル・ストリーミングテキスト表示・ロール別スタイリング(user / assistant / system)・入力欄・送信ボタン・ローディング状態・エラー状態で構成される複合コンポーネント。ChatGPT・Claude・Geminiなどのチャットインターフェースの設計パターンが標準化しつつあり、プロダクト内AIアシスタント・カスタマーサポートbot・コードアシスタントなど幅広い用途で使われる。

この記事を読むと、user/assistant/systemのロール別レイアウト・ストリーミング表示のアニメーション・Markdown内容のレンダリング・入力欄の高さ自動調整・aria-live でのストリーミング通知・中断ボタンの設計が自分でできるようになります。


1. UI例(Preview / Live)

実装で見る(GunjoUI)

この部品を、デザインシステム GUNJO の実装で確かめられます。

2. 定義(Definition)

LLM(大規模言語モデル)または会話型AIとユーザーが対話するためのUIコンポーネント群の総称。

メッセージのロール:

ロール説明表示位置
userユーザーの入力右寄せ・青系バブル
assistantAIの応答左寄せ・グレー系バブル
systemシステムプロンプト(通常非表示)UIに表示しないことが多い

3. 使い分け(When to use / When NOT to use)

3.1 When to use

  • AIアシスタント機能:製品内の質問応答・理解が必要なヘルプ
  • カスタマーサポートbot:FAQの自動応答・エスカレーション前の一次対応
  • コードアシスタント:コードの説明・バグ修正・リファクタリング提案
  • コンテンツ生成支援:文章の下書き・翻訳・要約

3.2 When NOT to use

  • 定型の手続き:フォームやウィザードの方が適切(住所入力・アカウント設定)
  • 単純なFAQ:検索可能なFAQページの方が早い
  • リアルタイム性が不要で構造化された選択:決定木形式のbotの方が予測可能

4. 設計判断の核(Decision Principles)

AI Chat UIの核は「ストリーミング中の状態管理」——AIの応答はストリーミング(逐次表示)で返ってくることが多く、「考え中」→「テキスト生成中」→「完了」の3状態を適切に表示することが、体感速度とユーザーの安心感に直結する。

判断の優先順位:① ストリーミング状態の表示 → ② 中断ボタンの提供 → ③ エラー状態の設計 → ④ aria-live でのアクセシビリティ

  • 「考え中」はドットアニメーション、「生成中」はカーソル点滅で区別する:APIの応答が来るまでの待機中はドット3つのバウンス、テキストが流れてくるストリーミング中はテキスト末尾のカーソル点滅を表示することで、ユーザーは「処理の段階」を直感的に理解できる
  • 中断ボタンを必ず提供する:ストリーミング中はテキストが長くなる可能性があり、ユーザーが途中で止めたいケースは多い。送信ボタンをストリーミング中は「停止ボタン(■)」に切り替えるUI変化が最も明確
  • エラー状態は応答バブル内にインライン表示し「再試行」ボタンを提供する:エラーをモーダルやトーストで表示すると、どのメッセージに対するエラーか分からなくなる。該当のAI応答バブルの位置に赤系のエラーバブルを表示し、再試行ボタンをその直下に配置する
  • テキストエリアは入力量に合わせて自動高さ調整する:textarea の高さを scrollHeight に合わせて自動伸長し、最大高さ(例:120px)を超えたらスクロール可能にする

5. 状態設計(States)

状態入力欄送信ボタンAI応答エリア
初期(空)プレースホルダー表示非活性なし
入力中テキスト表示活性—
考え中(waiting)disabled—ドットアニメーション
生成中(streaming)disabled停止ボタン(■)テキスト逐次表示+カーソル
完了再び有効送信ボタン完全なテキスト
エラー再び有効送信ボタンエラーバブル+再試行

6. バリエーション設計(Variants)

バリアント特徴使用例
全画面チャットメッセージ履歴が主役ChatGPT・Claude
サイドパネル型コンテンツと並列表示エディタのAIアシスタント
ポップオーバー型小さなウィジェットとして展開サポートbot・Intercom
インライン型テキスト選択後その場でAI操作Notion AI・Word Copilot

7. パターン集(Good / Bad / How to fix)

7.0 よく崩れる設計パターン(3つ)

  • ストリーミング中に入力が可能:前のメッセージの応答中に次のメッセージを送信でき、会話の順序が破綻する
  • エラー時に再試行手段がない:API呼び出しが失敗したとき、ユーザーは同じメッセージを手動でコピーして再入力する必要がある
  • メッセージ追加後にスクロールしない:新しいメッセージが表示されるたびに自動スクロールされず、ユーザーが手動でスクロールする必要がある

7.1 Bad(典型3つ)

  • ストリーミング中も <textarea> が有効で複数のリクエストを連続送信できる
  • AI応答のエラーをページ上部のトーストで通知し、どのメッセージのエラーか不明
  • <div> のスクロールコンテナに scrollTop の自動制御がなく新メッセージを見逃す

7.2 Good(対になる3つ)

  • isStreaming state で <textarea> と送信ボタンを disabled にし、ストリーミング中は停止ボタンのみ表示する
  • エラーバブルを当該メッセージ位置に赤系スタイルでインライン表示し、直下に「↺ 再試行」ボタンを配置する
  • useEffect(() => { messagesEndRef.current?.scrollIntoView({ behavior: 'smooth' }); }, [messages, streamingText]) で自動スクロールを実装する

7.3 How to fix(手順)

  1. isStreaming state で入力欄とボタンの活性/非活性を制御する
  2. ストリーミング中の送信ボタンを「停止(■)」に切り替え、クリックでストリーミングをキャンセルする
  3. エラーはメッセージバブルの位置にインラインで表示し、再試行ボタンを提供する
  4. メッセージリスト末尾に ref を置き、scrollIntoView で自動スクロールする

8. ルール(Must / Better)

Must(守らないと壊れる)

Better(品質が跳ねる)


9. アクセシビリティ要件(必須)

Screen Reader

<!-- メッセージログ全体 -->
<div
  role="log"
  aria-label="チャット履歴"
  aria-live="polite"
  aria-relevant="additions"
>
  <!-- ユーザーメッセージ -->
  <div role="article" aria-label="あなた">
    <p>Carouselをいつ使うべきか教えてください。</p>
  </div>

  <!-- AI応答 -->
  <div role="article" aria-label="AIアシスタント">
    <p>Carouselは以下の場面で有効です…</p>
  </div>
</div>

<!-- 入力欄 -->
<textarea
  aria-label="メッセージ入力"
  aria-describedby="input-hint"
/>
<p id="input-hint">Enter で送信、Shift+Enter で改行</p>

<!-- ストリーミング中の送信ボタン切り替え -->
<button aria-label="生成を停止">■</button>

10. 実装メモ(Implementation Notes)

  • Vercel AI SDK:useChat フックがストリーミング・メッセージ管理・エラー状態・中断(stop())をすべてカバーしており、AI Chat UIを構築する場合の第一候補
  • ストリーミング実装:OpenAI APIの stream: true + ReadableStream で逐次受信し、setStreamingText(prev => prev + chunk) で追記するパターンが基本
  • Markdown レンダリング:AI応答にMarkdownが含まれる場合は react-markdown + remark-gfm で安全にレンダリングする。dangerouslySetInnerHTML は使用しない
  • メッセージの永続化:会話履歴を localStorage または DB に保存する場合、messages stateを永続化するロジックを useEffect で実装する

11. 関連リンク


12. まとめ

AI Chat UIの設計で最重要なのは「ストリーミング中の状態管理」と「中断ボタンの提供」です。AIの応答はユーザーの期待と一致しないことも多く、途中で止めたいニーズは頻繁に発生します。role="log" + aria-live="polite" のアクセシビリティ実装と、エラー時のインライン再試行UIは必須実装です。実装コストを下げるためには Vercel AI SDK の useChat フックを活用することを強く推奨します。

更新のお知らせ

サイトに載せていない実例や、新しい記事のお知らせはこちらで出しています。

読んだ内容を、自分の画面に当てるとき

UIXHEROは、記事を書くほかに、画面の検品・判定、デザインシステムの構築、実装と改善の伴走を受けています。何を頼めばいいか決まっていない段階の相談も、同じ窓口で受けます。

UIXHEROに頼めることを見る

※ 記事の内容についての質問や、書いてほしいテーマの要望も同じ窓口で受けています

記事をシェア

メールでお知らせを受け取る

最終更新: 2026年9月14日

この記事を書いた人

Dengen Yosho(DGYS)

Dengen Yosho(DGYS)

UI/UXデザイナー兼デザインエンジニア デザイン歴25年以上 情報設計〜UIデザイン〜React/TypeScriptによる実装までを一気通貫で担当 大手企業のDXプロジェクトや決済アプリ領域で、デザインリードとして改善と構築を経験 現在はフリーランスとして、プロダクトのUI/UX改善とデザインシステム構築を支援 長年の実務の中で感じてきたのは、 「良いUI」はセンスではなく、再現可能な判断の積み重ねであるということ UIXHEROは、 心理学や行動科学の知見を、現場で使える設計言語に翻訳するための場所 関心領域は「ユーザーの行動が変わるUI」 人の認知・注意・意思決定の構造を理解し、 “なぜそのUIが機能するのか”を言語化することを目指している

あわせて読みたい

この記事に関連する記事をご紹介します

Day Band(いちにちの帯)

1日を1本の帯にして、時間帯を面で、節目を印で、いまの時刻とつまみを重ねて見せるUIコンポーネント。器が1日に固定されることの意味、4つの層の重ね方、印のラベルと時刻の数字を分ける理由、触った瞬間に動かさない理由を解説する。

2026年9月14日
約24分

Live Badge(LIVEの札)

隣の数字がいまの値かどうかを示す小さな札。状態を表す語を枠で囲って独立させる理由、明滅と色を補助に留める理由、実時間から外れたときに「古い」ではなく「いつの値か」を出す設計判断とARIA実装を解説する。

2026年9月14日
約21分

Time Transport(時間の操作盤)

いま映している時刻を、名前をつけた速さの段で動かし、決まった幅で飛ばし、ひと押しで「いま」へ戻すための操作盤。速さを連続値にしない理由、向きをアイコンに持たせる理由、状態を大きい表示の色で示さない理由を解説する。

2026年9月14日
約25分

もっと深く知りたいですか?

ここに掲載されていないトピックについても、リクエストがあれば解説記事を追加します。 わかりにくい点や、具体的な事例について知りたいことがあれば教えてください。

リクエストを送る