UIXHERO

Floating Panel(フローティングパネル)

画面上に浮かんだ状態で表示し続けるパネルUIコンポーネント。ユーザーがドラッグで位置を変えたり、折りたたんだりできる永続的なフローティングUIの設計・実装を解説する。

2026年3月3日
更新: 2026年9月3日
28
by Dengen Yosho(DGYS)

画面上に常時浮かんだ状態で表示し続けるパネルコンポーネント。Modal・Popoverと異なりバックグラウンドのコンテンツを操作しながら同時に参照・操作できることが特徴。図形編集ツールのプロパティパネル・ビデオ通話のミニプレーヤー(PiP)・AIチャットの補助パネル・デバッグコンソールなどで使われる。

この記事を読むと、Floating PanelとModal・Popoverの根本的な違い・ドラッグ移動の実装・折りたたみ(Collapse)設計・画面外へのはみ出し防止(境界制約)・フォーカス管理が自分でできるようになります。


1. UI例(Preview / Live)

実装で見る(GunjoUI)

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

2. 定義(Definition)

バックグラウンドのコンテンツを操作できる状態を保ちながら、画面上に常時浮かんで表示し続けるパネルUIコンポーネント。Modal(を操作不能にする)・Popover(クリックで開き焦点が移る)・Sheet(画面端からスライドする)と異なり、「常時表示・背景操作可・自由配置」 の3点が特徴。

Modal / Dialog との違い:Modalはaria-modal="true" + で背景を操作不能にする。Floating Panelは背景を操作できる状態で共存し、フォーカストラップは不要(むしろ付けてはいけない)。

Popover との違い:Popoverはクリックで開き、Escape/外クリックで閉じる一時的なパネル。Floating Panelは明示的に閉じるまで表示し続ける永続的なパネル。

Sheet / Drawer との違い:Sheetは画面端(下/左/右)にアンカーされる。Floating Panelは画面上の任意の位置に自由配置でき、ドラッグで移動できる。


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

3.1 When to use

  • 図形編集・デザインツールのプロパティパネル:キャンバスを操作しながら選択オブジェクトのプロパティを同時編集する
  • AIチャット補助パネル:メインコンテンツを参照しながらAIに質問・指示する
  • ビデオ通話のPicture-in-Picture:メインコンテンツを使いながら通話映像を継続表示する
  • デバッグコンソール / ログパネル:アプリを操作しながらリアルタイムログを確認する
  • ショッピングカートの常時表示:商品一覧を閲覧しながらカート内容を確認する

3.2 When NOT to use

  • 重要な確認・警告(削除確認・決済確認)→ Modal / Alert Dialog を使う(背景を遮断して注意を集中させる)
  • モバイルがメイン:スクリーンが小さくFloating Panelがコンテンツを覆う → Sheet / Drawerを使う
  • 一時的な補足情報(短い補足)→ Tooltip / Popoverで十分
  • コンテンツが多くスクロールが必要:Sheet / Drawer の方が適切

3.3 代替UI(Alternatives)

  • 重要な確認・操作 → Modal Dialog / Alert Dialog
  • 画面端からのパネル → Sheet / Drawer
  • 一時的な補足情報 → Popover / Tooltip
  • モバイルでの詳細表示 → Sheet / Drawer

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

Floating Panelの核は「背景と共存する補助性」——背景コンテンツの操作を妨げないことが大前提。重要な確認・必須の操作をFloating Panelに入れると、ユーザーがパネルを見落としたまま進んでしまう。

判断の優先順位:① 補助的コンテンツのみ(必須の操作を入れない)→ ② 境界(画面外はみ出し防止)→ ③ 折りたたみ対応 → ④ モバイルでのSheet代替

  • ドラッグ移動には境界制約を必ず実装する:パネルが画面外にはみ出すと閉じるボタンが見えなくなりパネルを操作できなくなる。Math.max(0, Math.min(maxX, x)) で左右・上下の境界に制約をかける
  • 折りたたみ(Collapse)ボタンで最小化できるようにする:パネルが邪魔な時にヘッダーだけの最小化状態にできると、閉じなくても邪魔にならない。aria-expanded でスクリーンリーダーに折りたたみ状態を伝える
  • モバイルではSheetに切り替える:スクリーン幅が小さい場合(768px未満)はFloating Panelでなく画面下からのSheetを使う。レスポンシブブレークポイントでコンポーネントを切り替える
  • role="dialog" + aria-label でパネルの目的を伝えるaria-modal="true" は付けない(背景を操作不能にしてはいけない)。スクリーンリーダーがパネルの存在を認識できるよう role="dialog"aria-label を付与する

5. 状態設計(States)

5.1 必須状態(Required)

  • Visible(表示中):デフォルト状態。任意の位置に表示
  • Closed(閉じた状態):閉じるボタンで非表示

5.2 条件付き状態(Conditional)

  • Collapsed(折りたたみ):ヘッダーのみ表示、コンテンツを非表示。aria-expanded="false"
  • Dragging(ドラッグ中)cursor: grabbing、テキスト選択を無効化(user-select: none
  • Minimized(最小化):コンパクトなアイコン状態に縮小(PiP等)
状態必須何を伝えるか
Visibleパネルが表示中(常時)
Closedパネルを閉じた(再表示手段を提供する)
Collapsedコンテンツを折りたたみ中(aria-expanded="false")
Dragging現在ドラッグ移動中

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

用途によってサイズ・機能が異なる。

バリアントドラッグ折りたたみ使用例
プロパティパネルデザインツール・編集ツール
AIチャットパネルAI補助チャット
PiP(ミニプレーヤー)ビデオ通話・メディア再生
デバッグパネル開発ツール・コンソール

禁止パターンaria-modal="true" を付与する → 背景がスクリーンリーダーに見えなくなり、Floating Panelが閉じるまで背景コンテンツを操作できなくなる(Modalと同等の動作になる)。


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

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

  • 境界制約がなくパネルが画面外にはみ出す:ユーザーがパネルをドラッグしすぎると閉じるボタンが画面外に消えてパネルを閉じられなくなる
  • モバイルでFloating Panelを使う:スマートフォンの小さな画面でFloating Panelがコンテンツを覆い、背景コンテンツを操作できなくなる(Floating Panelの意味がなくなる)
  • 重要な確認をFloating Panelに入れる:「本当に削除しますか?」のような確認をFloating Panelで実装すると、背景に隠れて見落とされたまま操作が続行される

7.1 Bad(典型3つ)

  • ドラッグ移動の制約なし:setPosition({ x: e.clientX, y: e.clientY }) でパネルが画面外にはみ出す
  • モバイルでもFloating Panelのまま:スクリーン幅が320pxでもFloating Panelを表示し、背景コンテンツの大半が隠れる
  • aria-modal="true" を付与:スクリーンリーダーで背景が操作不能になり、Floating Panelを閉じるまで他のコンテンツが「見えない」状態になる

7.2 Good(対になる3つ)

  • ドラッグ時に Math.max(0, Math.min(containerWidth - panelWidth, x)) で境界制約を実装し、パネルが常に画面内に収まる
  • useMediaQuery('(max-width: 768px)') でモバイルを検知し、<Sheet> に切り替えるレスポンシブ対応を実装する
  • role="dialog" + aria-label のみを付与し(aria-modal は付けない)、スクリーンリーダーに「ダイアログが開いています」とだけ伝える

7.3 How to fix(手順)

  1. ドラッグ処理に境界制約を追加:x = Math.max(0, Math.min(containerRef.current.offsetWidth - panelRef.current.offsetWidth, newX))
  2. aria-modal="true" を削除し、role="dialog" + aria-label だけを残す
  3. window.innerWidth または CSS の @media でモバイル幅を検知し、Sheet への切り替え処理を追加する
  4. ドラッグ中は user-select: none をドキュメントに付与してテキスト選択を防ぐ(ドラッグ終了時に解除)

8. ルール(Must / Better)

Must(守らないと壊れる)

Better(品質が跳ねる)


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

Keyboard

  • Tab でパネル内のインタラクティブ要素を移動
  • Escape でパネルを閉じる(フォーカスをパネルを開いたトリガーに戻す)
  • ドラッグ移動をキーボードで行う場合:矢印キー(10pxずつ移動)+ Shift で粗い移動(50pxずつ)

Focus

  • パネルが開いた時:最初のインタラクティブ要素にフォーカスを移す(任意)またはパネルコンテナ自体にフォーカスする
  • aria-modal="true"付けない:付けるとフォーカストラップが発生して背景が操作不能になる
  • Floating Panel内のコントロールは通常の Tab 順序でフォーカス可能

Screen Reader

<div
  role="dialog"
  aria-label="プロパティパネル"
>
  <!-- パネルコンテンツ -->
  <!-- aria-modal は付けない -->
</div>

折りたたみボタンには aria-expanded を付与:

<button aria-expanded="false" aria-label="パネルを展開">▲</button>

Touch / Pointer

  • タッチデバイスでのドラッグ移動:onTouchStart / onTouchMove / onTouchEnd でタッチドラッグを実装する
  • (閉じるボタン・折りたたみボタン)は最低44×44px
  • モバイル(768px未満)ではFloating PanelをSheetに切り替える

10. 実装メモ(Implementation Notes)

  • shadcn/ui には Floating Panel のネイティブコンポーネントがない。@dnd-kit/coreuseDraggable を使うと、センサー・境界制約・アクセシビリティ対応のドラッグ移動が実装できる
  • シンプルなドラッグ実装は onMouseDowndocument.addEventListener('mousemove')document.addEventListener('mouseup') のパターン(本で採用)。pointer-events を使うと mousedownpointermovepointerup でタッチも同時対応できる
  • パネル位置の永続化:useEffectlocalStorage.setItem('panel-position', JSON.stringify(position)) を呼び、初期値を JSON.parse(localStorage.getItem('panel-position')) から読み込む
  • Framer Motion の drag prop + dragConstraints を使うと、付きのドラッグ移動と境界制約が宣言的に実装できる(<motion.div drag dragConstraints={containerRef} />

11. 関連リンク


12. まとめ

Floating Panelの設計で最重要なのは「背景と共存する補助性の徹底」と「aria-modal を付けないこと」です。迷ったら 4. 設計判断の核 に戻り、「補助的コンテンツのみか(必須操作が入っていないか)」「ドラッグに境界制約があるか」「aria-modal="true" を付けていないか」の3点を確認してください。モバイル対応はSheetへの切り替えが最もシンプルな解決策です。ModalとFloating Panelの選択基準は「背景を遮断してユーザーの注意を集中させる必要があるか」——必要ならModal、背景操作と共存させたい補助機能ならFloating Panelです。

更新のお知らせ

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

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

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

UIXHEROに頼めることを見る

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

記事をシェア

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

最終更新: 2026年9月3日

この記事を書いた人

Dengen Yosho(DGYS)

Dengen Yosho(DGYS)

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

あわせて読みたい

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

Bar Chart(棒グラフ)

カテゴリごとの量を棒の長さで比べるチャート。ゼロ基線の扱い、並び順、縦横の選び方、しきい値の見せ方という設計判断と、色だけに頼らないアクセシビリティ要件を解説する。

2026年8月27日
18

Donut Chart(ドーナツチャート)

中央をくり抜いた円で構成比を示すチャート。中央に置く値の選び方、円グラフとの使い分け、リングの太さ、凡例の作りという設計判断と、色だけに頼らないアクセシビリティ要件を解説する。

2026年8月27日
17

Gauge Chart(ゲージチャート)

1つの値を範囲の中に置いて示す半円のチャート。範囲の両端に意味があるかという条件、しきい値の帯の設計、色だけで良否を伝えない書き方という設計判断とアクセシビリティ要件を解説する。

2026年8月27日
16

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

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

リクエストを送る