# 【Flutter web】ボタンがクリックできない？pointer_interceptorで解決

> Flutter webでHtmlElementView上のFlutterオブジェクトがクリック・タップできない解決方法。pointer_interceptorパッケージでHtmlElementView/PlatformViewウィジェット上に重ねたFlutterウィジェットクリックできるようにします。

- 公開日: 2025-08-28
- 著者: Matsu
- タグ: Flutter
- URL: https://tech.anycloud.co.jp/articles/flutter-web-pointer-interceptor

---

## Flutter webでモーダル上のボタンなどがクリックできない謎

既存のFlutterアプリをweb化もして動作確認していたところ、Youtube動画のiframeを表示している画面でモーダルを表示してモーダルの「はい」「いいえ」のボタンをクリックしてみました。

なぜかYoutube動画の再生停止ボタンをクリックしたことになっていて、モーダル上のボタンがクリックできていません。

```dart
KeyboardDismissOnTap(
	dismissOnCapturedTaps: false,
	child: Dialog(),
),
```

初めは、`KeyboardDismissOnTap`が原因かと思いましたが、削除しても治らない…

## Flutter webでボタンなどがクリックできない原因

<figure><img src="./image-001.webp" alt="Flutter webでボタンなどがクリックできない原因" width="1600" height="662"></figure>

> *In the dashed areas, mouse events won't work as expected. The* `HtmlElementView` will consume them before Flutter sees them. （破線の部分では、マウスイベントは期待通りに動作しません。Flutterがそれを見る前にHtmlElementViewがそれを消費してしまう。）

なるほど。。。

マウスジェスチャーに反応する`HtmlElementView` や `PlatformView`ウィジェットの上にFlutterウィジェットを重ねると、クリックは`HtmlElementView` や `PlatformView`によって消費され、Flutterには中継されないみたいです。

その結果、FlutterウィジェットのonTapハンドラは期待通りに発火しないんですね。

## HtmlElementView上でもonTapを実行するためにpointer\_interceptorパッケージで解決

<div class="link-card-wrap"><a class="link-card" href="https://pub.dev/packages/pointer_interceptor" target="_blank" rel="noopener noreferrer"><span class="link-card-body"><span class="link-card-title">pointer_interceptor | Flutter package</span><span class="link-card-description">A widget to prevent clicks from being swallowed by underlying HtmlElementViews on the web.</span><span class="link-card-meta"><img class="link-card-favicon" src="./linkcard-01-favicon.webp" alt=""><span class="link-card-domain">pub.dev</span></span></span><img class="link-card-image" src="./linkcard-01-image.webp" alt=""></a></div>

`PointerInterceptor`を使うことで、Web 上の基盤によってマウスイベントがキャプチャされるのを防ぐウィジェットです。

<figure><img src="./image-002.webp" alt="HtmlElementView上でもonTapを実行するためにpointer_interceptorパッケージで解決" width="1614" height="702"></figure>

各`PointerInterceptor`（緑）はFlutterウィジェットとその下のHtmlElementViewの間でレンダリングします。

マウスイベントが背景のHtmlElementViewに届かないようになり、期待通りに動くようになりました。

```dart
kIsWeb
  ? PointerInterceptor(
      child: Dialog(),
    )
  : KeyboardDismissOnTap(
      dismissOnCapturedTaps: false,
      child: Dialog(),
    ),
```

### 注意点：多用するとパフォーマンスが悪化する

> Using multiple `PointerInterceptor` instances on iOS can be slow and increases memory usage due to the performance overhead of the underlying platform view.

iOSで複数の`PointerInterceptor`インスタンスを使用すると、基盤となるプラットフォーム ビューのパフォーマンス オーバーヘッドにより、速度が低下し、メモリ使用量が増加する可能性があります。

## まとめ

Flutter Webでは、`HtmlElementView` や `PlatformView`（今回のケースだとYouTubeの `<iframe>`）が背面にあると、その領域がタップやクリックイベントを奪ってしまい、上に重ねたFlutterウィジェットのボタンが反応しないという落とし穴がありました。

Web特有の挙動なので、モバイルアプリ開発だけだと気づきにくいですが、実際に遭遇してみると「なぜボタンが効かないのか？」という謎が理解できました。

今後、Flutterを Webに展開する際は、HtmlElementViewのクリック競合問題とPointerInterceptorの活用 を覚えておくと安心です。
