You are currently viewing Flutter: AbsorbPointer vs IgnorePointer – What’s the Difference?

Flutter: AbsorbPointer vs IgnorePointer – What’s the Difference?

In Flutter, touch events — like taps, drags, and swipes — are handled using what’s called pointer events. Sometimes, you may want certain widgets to stop responding to these touches. This could be to disable a button, block user interaction during a loading state, or create overlays that ignore input.

Flutter provides two powerful widgets to help with this: AbsorbPointer and IgnorePointer. At first glance, they seem to do the same thing — but they behave differently, especially when used in a Stack.

In this article, we’ll explore what each widget does, how they’re different, and when to use them.

What is AbsorbPointer?

AbsorbPointer is a widget that prevents its child and all its descendants from receiving pointer events, such as taps or gestures. The key word here is “absorb” — it receives the event but doesn’t pass it on.

You can think of it like a sponge that soaks up all input: the touch doesn’t reach the child widget, and it doesn’t go beyond the sponge either.

import 'package:flutter/material.dart';

void main() {
  runApp(const AbsorbPointerExample());
}

class AbsorbPointerExample extends StatelessWidget {
  const AbsorbPointerExample({super.key});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      debugShowCheckedModeBanner: false,
      theme: ThemeData(
        colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple),
      ),
      home: const AbsorbPointerHome(),
    );
  }
}

class AbsorbPointerHome extends StatelessWidget {
  const AbsorbPointerHome({super.key});

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        backgroundColor: Theme.of(context).colorScheme.inversePrimary,
        title: const Text("Flutter: AbsorbPointer"),
      ),
      body: Center(
        child: AbsorbPointer(
          absorbing: true, // Absorbs all touch events
          child: ElevatedButton(
            onPressed: () {
              ScaffoldMessenger.of(
                context,
              ).showSnackBar(const SnackBar(content: Text("You Tapped Me!")));
            },
            child: Text("Tap Me"),
          ),
        ),
      ),
    );
  }
}

In this example, the button still appears on screen, but it’s completely non-interactive. Any tap is absorbed and discarded.

AbsorbPointer Demo

What is IgnorePointer?

IgnorePointer, on the other hand, makes its child invisible to pointer events. It doesn’t receive the event at all — the gesture is effectively ignored. However, unlike AbsorbPointer, the event can continue to propagate to widgets behind it.

You can think of it like a ghost: it doesn’t interact with touches, and your tap can pass right through it to hit something behind.

import 'package:flutter/material.dart';

void main() {
  runApp(const IgnorePointerExample());
}

class IgnorePointerExample extends StatelessWidget {
  const IgnorePointerExample({super.key});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      debugShowCheckedModeBanner: false,
      theme: ThemeData(
        colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple),
      ),
      home: const IgnorePointerHome(),
    );
  }
}

class IgnorePointerHome extends StatelessWidget {
  const IgnorePointerHome({super.key});

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        backgroundColor: Theme.of(context).colorScheme.inversePrimary,
        title: const Text("Flutter: IgnorePointer"),
      ),
      body: Center(
        child: IgnorePointer(
          ignoring: true, // Ignores all touch events
          child: ElevatedButton(
            onPressed: () {
              ScaffoldMessenger.of(
                context,
              ).showSnackBar(const SnackBar(content: Text("You Tapped Me!")));
            },
            child: Text("Tap Me"),
          ),
        ),
      ),
    );
  }
}

Here too, the button looks active, but it doesn’t respond to taps — and importantly, the gesture may reach other widgets underneath.

IgnorePointer Demo

Key Differences

The key difference between AbsorbPointer and IgnorePointer is how they handle event propagation, especially in layered interfaces like Stack.

FeatureAbsorbPointerIgnorePointer
Receives pointer events✅ Yes (but does not pass to child)❌ No (ignores all events)
Child receives pointer events❌ No❌ No
Widgets below in a Stack receive the event❌ No✅ Yes
Child widget is still visible✅ Yes✅ Yes

In short:

  • AbsorbPointer stops the event.
  • IgnorePointer lets the event pass through.

A Practical Example Using Stack

Let’s look at a real-world case. Suppose you have two buttons, one stacked on top of the other using a Stack. You want to disable the top button temporarily.

Let’s see how each pointer widget behaves in this scenario.

IgnorePointer Example

Here’s a Flutter app where the top button is wrapped in an IgnorePointer. The top button will ignore any touch — but the tap will pass through to the bottom button.

import 'package:flutter/material.dart';

void main() {
  runApp(const IgnorePointerExample());
}

class IgnorePointerExample extends StatelessWidget {
  const IgnorePointerExample({super.key});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      debugShowCheckedModeBanner: false,
      theme: ThemeData(
        colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple),
      ),
      home: const IgnorePointerHome(),
    );
  }
}

class IgnorePointerHome extends StatelessWidget {
  const IgnorePointerHome({super.key});

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        backgroundColor: Theme.of(context).colorScheme.inversePrimary,
        title: const Text("Flutter: (Absorb | Ignore) Pointer"),
      ),
      body: Center(
        child: Stack(
          children: [
            ElevatedButton(
              onPressed: () {
                ScaffoldMessenger.of(
                  context,
                ).showSnackBar(const SnackBar(content: Text("Bottom tapped!")));
              },
              child: Text("Bottom Button"),
            ),
            IgnorePointer(
              ignoring: true, // Ignores all touch input
              child: ElevatedButton(
                onPressed: () {
                  ScaffoldMessenger.of(
                    context,
                  ).showSnackBar(const SnackBar(content: Text("Top tapped!")));
                },
                child: const Text("Top Button"),
              ),
            ),
          ],
        ),
      ),
    );
  }
}

  • Tap on the top button → Nothing happens
  • But the bottom button responds — because the event passes through
IgnorePointer Stack Demo

This is useful when you want to block interaction on a widget without affecting those underneath it.

AbsorbPointer Example

Now let’s change the IgnorePointer to AbsorbPointer. Here’s the modified code:

import 'package:flutter/material.dart';

void main() {
  runApp(const AbsorbPointerExample());
}

class AbsorbPointerExample extends StatelessWidget {
  const AbsorbPointerExample({super.key});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      debugShowCheckedModeBanner: false,
      theme: ThemeData(
        colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple),
      ),
      home: const AbsorbPointerHome(),
    );
  }
}

class AbsorbPointerHome extends StatelessWidget {
  const AbsorbPointerHome({super.key});

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        backgroundColor: Theme.of(context).colorScheme.inversePrimary,
        title: const Text("Flutter: (Absorb | Ignore) Pointer"),
      ),
      body: Center(
        child: Stack(
          children: [
            ElevatedButton(
              onPressed: () {
                ScaffoldMessenger.of(
                  context,
                ).showSnackBar(const SnackBar(content: Text("Bottom tapped!")));
              },
              child: Text("Bottom Button"),
            ),
            AbsorbPointer(
              absorbing: true, // absorbs all touch input
              child: ElevatedButton(
                onPressed: () {
                  ScaffoldMessenger.of(
                    context,
                  ).showSnackBar(const SnackBar(content: Text("Top tapped!")));
                },
                child: const Text("Top Button"),
              ),
            ),
          ],
        ),
      ),
    );
  }
}

  • Tap on the top button → Nothing happens
  • The bottom button also doesn’t respond — because the event was absorbed
AbsorbPointer Stack Demo

This is great when you want to block user interaction across multiple layers. However, it’s important to note:

If the widgets underneath are visibly exposed (i.e. not fully covered visually), users may still be able to tap them directly.

This happens because AbsorbPointer only absorbs events in its own bounds — it doesn’t block the screen globally like a modal or barrier. To fully block background taps, make sure the absorbing widget covers the whole screen area you want to protect.

When to Use What?

ScenarioUse
Disable a widget completely (no interaction)AbsorbPointer
Disable interaction for a child but let touches pass to widgets belowIgnorePointer
Create a loading overlay that blocks inputAbsorbPointer
Animate a widget without blocking other contentIgnorePointer

Conclusion

Both AbsorbPointer and IgnorePointer help you control touch behavior in Flutter, but they serve slightly different purposes:

  • Use AbsorbPointer when you want to block pointer events from reaching the widget and anything beneath it.
  • Use IgnorePointer when you want the widget to ignore input but still allow interaction with widgets behind it.

Understanding how these widgets work — especially when using a Stack — helps you design smarter, more intuitive UIs.