show<T> static method

Future<T?> show<T>({
  1. required BuildContext context,
  2. required List<CNActionSheetAction<T>> actions,
  3. String? title,
  4. String? message,
  5. String? cancelLabel,
  6. Rect? anchorRect,
})

Presents the action sheet and resolves to the selected action's CNActionSheetAction.value.

Resolves to null when the sheet is cancelled, dismissed by tapping outside, or when the selected action carries no value.

title and message are the sheet's header. cancelLabel adds a cancel-styled button. From iOS 26 the system supplies one of its own for a centred sheet, so passing null is safe there; below iOS 26 UIKit adds nothing, and a sheet with no cancel row can only be left by picking one of its actions. Pass a cancelLabel unless forcing a choice is the point.

A call with no cancelLabel and no enabled action would present a sheet with nothing to press — below iOS 26 one that cannot be dismissed at all — so it asserts in debug and resolves to null without presenting anything in release.

Apple's Human Interface Guidelines recommend at most four buttons including cancel. Longer lists work, but scroll.

Implementation

static Future<T?> show<T>({
  required BuildContext context,
  required List<CNActionSheetAction<T>> actions,
  String? title,
  String? message,
  String? cancelLabel,
  Rect? anchorRect,
}) {
  assert(
    cancelLabel != null || actions.any((a) => a.enabled),
    'CNActionSheet.show needs a cancelLabel or at least one enabled action: '
    'a sheet with neither has nothing to press and never resolves.',
  );
  // `actions` is often built from a collection that can come out empty, and
  // `enabled` is often computed per action from one flag that can be false
  // for all of them. With no cancel button either, the native sheet has no
  // button that answers a tap and, below iOS 26, no dismissal path, so none
  // of the paths that complete the call can run and the caller's await hangs
  // for the life of the process. Answer it here instead of presenting a
  // modal there is no way out of.
  if (cancelLabel == null && !actions.any((a) => a.enabled)) {
    return Future<T?>.value(null);
  }

  if (defaultTargetPlatform != TargetPlatform.iOS) {
    return _showFallback<T>(
      context: context,
      actions: actions,
      title: title,
      message: message,
      cancelLabel: cancelLabel,
    );
  }

  return _showNative<T>(
    actions: actions,
    title: title,
    message: message,
    cancelLabel: cancelLabel,
    anchorRect: anchorRect,
  );
}