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.

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.

Key Differences
The key difference between AbsorbPointer
and IgnorePointer
is how they handle event propagation, especially in layered interfaces like Stack
.
Feature | AbsorbPointer | IgnorePointer |
---|---|---|
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

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

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?
Scenario | Use |
---|---|
Disable a widget completely (no interaction) | AbsorbPointer |
Disable interaction for a child but let touches pass to widgets below | IgnorePointer |
Create a loading overlay that blocks input | AbsorbPointer |
Animate a widget without blocking other content | IgnorePointer |
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.