-
Notifications
You must be signed in to change notification settings - Fork 0
LayrzSnackbar
A Material-free snackbar component displaying transient feedback messages in a stacked overlay with title, description, severity typing, and optional custom styling.
Metadata
Mirrors: ThemedSnackbar and ThemedSnackbarMessenger (layrz_theme)
Phase: M5 (Feedback layer)
Domain: Feedback
Primitive: Built on Overlay and OverlayEntry (Flutter SDK)
Status: Confirmed scope.
LayrzSnackbar is a feedback component that renders a single transient notification. It is always displayed and managed through the LayrzSnackbarMessenger ancestor widget, which owns the overlay stack, queue, and dismiss logic.
-
Title and description always paired: both
titleTextanddescriptionTextare mandatory string parameters (no Widget labels). -
Severity typing: a
typeenum drives icon and color selection, defaulting to success. -
Custom styling contract:
iconandcolorparameters are only valid whentypeis.custom; supplying them for any other type triggers a debug assertion. - External lifecycle: the caller supplies the snackbar instance to the messenger; the messenger owns stacking, animation, and dismissal.
- Stack-based rendering: multiple simultaneous snackbars stack vertically, displayed on the top right (desktop/tablet) or adapted positioning (mobile).
// Design sketch — illustrative only
class LayrzSnackbar {
/// The human-readable title displayed at the top of the snackbar.
///
/// Required. No Widget parameter is supported; only plain text.
final String titleText;
/// The descriptive message content shown below the title.
///
/// Required. This is the primary feedback content.
final String descriptionText;
/// The severity type driving color and icon selection.
///
/// Defaults to `.success`. One of: .success, .error, .warning, .info, .context, .custom.
/// When .custom, [icon] and [color] must both be supplied.
/// For any non-custom type, [icon] and [color] must be null.
final LayrzSnackbarType type;
/// Custom icon displayed in the snackbar.
///
/// Only valid when [type] is .custom. Must be null for any other type.
/// A debug assertion enforces this contract.
final IconData? icon;
/// Custom background color for the snackbar.
///
/// Only valid when [type] is .custom. Must be null for any other type.
/// A debug assertion enforces this contract.
final Color? color;
/// Duration for which the snackbar is displayed before auto-dismissing.
///
/// Defaults to 10 seconds. Must be greater than zero.
final Duration duration;
/// Callback invoked when the snackbar is tapped.
///
/// When supplied, tapping the snackbar invokes this callback AND dismisses the snackbar.
/// If not supplied, the snackbar is not directly tappable (dismissal is via timeout or manual close affordance).
final VoidCallback? onTap;
/// Whether the snackbar displays a manual dismiss affordance (close button).
///
/// Defaults to true. When true, a close icon button is rendered, allowing manual dismissal
/// independent of the timeout.
final bool isDismissible;
}The type enum defines six severity categories, each with a standard color and icon from the theme:
enum LayrzSnackbarType {
/// Default type; requires [icon] and [color] to be supplied.
custom,
/// Success notification: green background, checkmark-like icon.
success,
/// Error notification: red background, error icon.
error,
/// Warning notification: orange background, warning icon.
warning,
/// Informational notification: blue background, info icon.
info,
/// Contextual notification: theme-dependent background.
context,
}LayrzSnackbarMessenger is an ancestor widget that hosts the overlay layer and manages the snackbar stack. It should wrap the entire app or a major section of the widget tree.
// Design sketch — illustrative only
class LayrzSnackbarMessenger extends StatefulWidget {
/// The child widget tree that will use the snackbar system.
final Widget child;
/// Maximum width for the snackbar display.
///
/// If not supplied, a sensible default is used (e.g., 400 logical pixels).
final double? maxWidth;
/// Padding around the snackbar stack.
///
/// Defaults to EdgeInsets.all(16). Controls spacing from screen edges.
final EdgeInsetsGeometry padding;
/// Whether snackbars should be rendered with accessibility announcements.
///
/// Defaults to true.
final bool enableAccessibility;
}To show a snackbar:
// Design sketch — illustrative only
LayrzSnackbarMessenger.of(context).show(
LayrzSnackbar(
titleText: 'Changes Saved',
descriptionText: 'Your profile has been updated successfully.',
type: .success,
),
);When multiple snackbars are shown without dismissal, they stack vertically on the screen. The exact positioning and stacking order is determined by the messenger's configuration:
- Desktop / Tablet: Snackbars are stacked on the top-right corner of the screen, growing downward as new snackbars are added.
- Mobile: Positioning is adapted to the available screen size; may stack differently based on device dimensions.
- Order: Newer snackbars are stacked below (or above) existing ones — the exact order is an implementation detail and will be finalized during M5 implementation.
When a snackbar's duration expires, it auto-dismisses and is removed from the stack. Remaining snackbars remain visible.
A snackbar can be dismissed in three ways:
-
Timeout: When the
durationexpires, the snackbar automatically dismisses. -
Manual close button: When
isDismissible = true, a close icon (✕) is rendered on the snackbar. Tapping it dismisses the snackbar immediately. -
Tap callback: When
onTapis supplied, tapping the snackbar invokes the callback and dismisses the snackbar.
When type is .custom:
- Both
iconandcolormust be supplied (non-null). - A debug assertion enforces:
assert(icon != null && color != null, 'Custom snackbar requires both icon and color').
When type is any non-custom value (.success, .error, .warning, .info, .context):
- Both
iconandcolormust be null. - A debug assertion enforces:
assert(icon == null && color == null, 'Non-custom type must have null icon and color').
This contract ensures clarity: either the type drives the appearance, or the caller explicitly provides both dimensions.
-
M1 Theme System (
LayrzTheme,LayrzThemeData) — color tokens for non-custom types. -
Flutter SDK Overlay (
Overlay,OverlayEntry) — rendering surface and entry/exit animation.
-
Stacking direction and order: Should newer snackbars appear above or below existing ones? Is there a maximum stack size before older ones are auto-dismissed?
-
Animation timing and curve: What is the entry/exit animation duration and Curve? The layrz_theme constant
kSnackbarAnimationDuration = 300msis available for reference, but the animation profile (curve type) is TBD. -
Accessibility announcements: Should snackbars trigger Semantics announcements on entry (e.g.,
onShow)? If yes, should the announcement include both title and description, or only one? -
Pause on hover: Does the auto-dismiss timeout pause when the user hovers over the snackbar on desktop? Or does it continue counting down?
-
Icon and color source for non-custom types: Are icons sourced from
layrz_icons? If so, which specific icon is paired with each severity type? -
Touch target size: When
isDismissible = true, what is the minimum tap target size for the close button? Should it meet Material's 48×48 dp minimum?
Critical path item: A design reference (Figma, annotated screenshot, or visual spec) must be attached to the LayrzSnackbar component before implementation begins. This specification must cover:
- Snackbar chrome: padding, border radius, shadow (if any).
- Title and description typography and spacing.
- Icon sizing and placement.
- Close button affordance size and position (when
isDismissible = true). - Background color and contrast for all six type variants in light and dark themes.
- Entry/exit animation (duration, curve, direction).
- Stacking layout (vertical spacing between multiple snackbars).
- Mobile adaptation (screen size < tablet breakpoint).
- Hover state on desktop (if applicable).
- Accessibility: focus indicators, announcements, keyboard navigation.
Last updated: 2026-08-13
Related documents: Input Contract, Design Tokens, Architecture
Made with ❤️ by Golden M, Inc.
- LayrzTextInput
- LayrzSelectableAction
- LayrzSelectionToolbar
- LayrzTextSelectionControls
- LayrzSelectionMagnifier
- LayrzSelectionHandlePainter
- LayrzTextAreaInput
- LayrzComboBoxInput
- LayrzNumberInput
- LayrzPasswordInput
- LayrzCheckboxInput
- LayrzRadioInput
- LayrzSelectInput
- LayrzMultiSelectInput
- LayrzSearchInput
- LayrzDualListInput
- LayrzDurationInput