Skip to main content

What are surface observers?

Surface observers are widgets that watch a specific surface slot and react to active item changes. They provide a simple, reactive way to build custom UI that responds to Presentum state without the overhead of popup-specific features. The PresentumActiveSurfaceItemObserverMixin handles all the complexity of:
  1. Subscribing to surface state - Automatically observes the correct slot
  2. Tracking active item changes - Detects when items activate or deactivate
  3. Managing lifecycle - Cleans up observers when widget disposes
  4. Handling initial state - Optionally processes the initial active item
Use surface observers for snackbars, banners, overlays, animations, or any UI that needs to react to surface state changes without showing dialogs.

Basic usage

Here’s a minimal surface observer:

Required implementations

You must implement two members:

Understanding state transitions

The onActiveItemChanged callback receives both current and previous items, enabling you to handle all state transitions:
A new item became active on an empty surface:
The active item became inactive:
The active item was replaced by another:

Production example: Update snackbar

This observer shows a snackbar when app updates are available:
See full source →
This observer doesn’t need popup-specific features like duplicate detection or conflict resolution - it simply shows/hides a snackbar based on state.

When NOT to use surface observers

Do not use surface observers for side effects or business logic that doesn’t involve UI rendering.If your observer’s build() method just returns widget.child with no UI changes, you’re using the wrong tool. Use Transition observers instead.
Examples of incorrect usage:
  • Triggering API calls when surface state changes
  • Starting/stopping timers based on state
  • Logging or analytics
  • BLoC/Provider integration
These are side effects and belong in transition observers, not widget-based observers.

Optional configuration

Handle initial state

Control whether to process the initial active item in initState:
Set to false if you only want to react to changes, not the initial state.

Access current active item

You can access the current active item at any time:

Access the observer

For advanced use cases, you can access the underlying observer:

When to use surface observers

Use PresentumActiveSurfaceItemObserverMixin only when you need to render UI based on surface state:

Snackbars & Banners

Show/hide snackbars, banners, toasts, or badges based on surface state

Visual Overlays

Display non-modal overlays or floating UI elements

UI Animations

Trigger widget animations tied to surface state changes

Dynamic Widgets

Render or update widgets based on active items
Key indicator: Your build() method returns actual UI or your widget manages visible elements.

Best practices

Leverage Dart 3 pattern matching to make state transitions explicit:
Always cancel timers, subscriptions, or animations:
Consider all possible state transitions:
Avoid heavy computation in the callback. Use scheduleMicrotask or Future for async work:

Next steps

Popup hosts

Learn about popup surface management with dialogs

Surfaces

Understand surfaces and slots

Production examples

Explore the complete example app