Skip to main content

Command Palette

Search for a command to run...

AbsorbPointer vs IgnorePointer in Flutter

Updated
4 min read
F
Thinking...

Are taps reaching the widget you expect? Learn how AbsorbPointer and IgnorePointer control touch events so you can block or let gestures pass through intentionally.

Why pointer control matters

When you build UIs you often want parts of the screen to ignore taps (e.g., a disabled control) or to block taps (e.g., a modal overlay). Flutter resolves touches with hit testing: widgets that participate in hit testing can receive pointer events. AbsorbPointer and IgnorePointer let you change how a subtree participates in hit testing.

Summary: Use these widgets to control whether a subtree handles pointer events or lets them pass through.

What each widget does

  • AbsorbPointer: Participates in hit testing and "absorbs" pointer events. Its children do not receive pointer events, and the events do not reach widgets behind AbsorbPointer in the tree.

  • IgnorePointer: Removes itself and its subtree from hit testing. Its children do not receive pointer events, and pointer events can pass through to widgets visually behind it.

Define acronyms: "UI" = user interface.

Summary: AbsorbPointer blocks events from reaching children and widgets behind; IgnorePointer keeps children from receiving events but lets events pass through.

Quick code demo

This minimal example shows the difference. Tap the blue container to see whether the background detector receives the tap.

// Dart / Flutter
class PointerDemo extends StatefulWidget {
  @override
  _PointerDemoState createState() => _PointerDemoState();
}

class _PointerDemoState extends State<PointerDemo> {
  bool useAbsorb = true;

  @override
  Widget build(BuildContext context) {
    return Stack(
      children: [
        GestureDetector(
          onTap: () => print('Background tapped'),
          child: Container(color: Colors.amber, height: 300),
        ),
        Center(
          child: useAbsorb
              ? AbsorbPointer(
                  child: ColoredBox(color: Colors.blue.withOpacity(0.7), child: SizedBox(width: 200, height: 100)),
                )
              : IgnorePointer(
                  child: ColoredBox(color: Colors.blue.withOpacity(0.7), child: SizedBox(width: 200, height: 100)),
                ),
        ),
        Positioned(bottom: 20, left: 20, child: ElevatedButton(onPressed: () => setState(() => useAbsorb = !useAbsorb), child: Text('Toggle Absorb/Ignore'))),
      ],
    );
  }
}

If useAbsorb is true: tapping the blue area prints nothing (AbsorbPointer absorbs and blocks background).
If useAbsorb is false: tapping the blue area prints "Background tapped" (IgnorePointer lets event pass through).

Summary: Try the toggle to observe the behavioral difference.

Common use cases

  • Disable a button visually but still allow background gestures: use IgnorePointer.

  • Block all interactions while showing a loading overlay: use AbsorbPointer (or ModalBarrier).

  • Make a control temporarily non-interactive while keeping it in the widget tree: either widget works depending on whether you want underlying widgets to receive taps.

Summary: Choose IgnorePointer when you want passthrough; choose AbsorbPointer when you want to block.

Interaction with transparency and layout

Both widgets do not change layout or visibility. A fully transparent Container wrapped in AbsorbPointer still blocks taps; wrapped in IgnorePointer it does not block them. That means a visually invisible widget can still affect hit testing depending on which one you use.

Summary: Visual transparency does not imply hit-test transparency.

Accessibility and semantics

These widgets primarily affect pointer hit testing. They do not automatically remove semantic nodes used by assistive technologies. If you want to remove a subtree from accessibility tools, combine these with ExcludeSemantics or adjust semantics explicitly.

Summary: Use ExcludeSemantics or semantic tweaks if you need to change accessibility exposure.

Performance notes

Both widgets are lightweight. Avoid complex logic inside builders triggered by pointer changes; toggling the widget state is cheap. Prefer const constructors when possible.

Summary: Performance differences are negligible; focus on correct semantics.

Common pitfalls

  • Expecting AbsorbPointer to let events reach widgets behind it — it does not.

  • Using IgnorePointer to "disable" a widget without visual feedback — users may not know the control is inactive.

  • Forgetting to update semantics after disabling interactions — this can confuse screen-reader users.

Summary: Test both interaction behavior and UX/semantics when disabling controls.

Conclusion & next steps

AbsorbPointer absorbs and blocks events; IgnorePointer ignores its subtree for hit testing and lets events pass through. Use AbsorbPointer for blocking overlays and IgnorePointer when you want passthrough behavior. Combine these with visual states (opacity, color, icons) and semantics adjustments for a complete UX.

Try this: build a small overlay with a loading spinner that uses AbsorbPointer to block interaction and a semi-transparent color to indicate disabled state. Then try the same with IgnorePointer to see how touch handling changes.