Skip to main content
← back

app bottom sheet

lib/app_bottom_sheet.dart · flutter · dart

a bottom sheet for flutter in one file. handle, title, message, theme-aware surface. no packages, no DI, no widget wrapping.

llms.txt

tldr

copy one file into your project, call showAppBottomSheet. no setup, no init call.

await showAppBottomSheet<void>(
  context: context,
  title: "Appearance",
  message: "How the app should look on this device.",
  child: ThemeModePicker(),
);

transparent modal host + painted sheet surface, so colors rebuild with the active theme while the sheet stays open. bottom corners track the device bezel.

live demo

starting the demo

install

copy one file

grab it and drop it in at lib/app_bottom_sheet.dart.

app_bottom_sheet.dart541 lines

it imports dart:ui, foundation, and material from the flutter sdk. nothing goes in pubspec.yaml.

use it

there is no init call. the defaults stand on their own.

await showAppBottomSheet<void>(
  context: context,
  title: "Saved filters",
  child: FiltersList(),
);

usage

title and message are optional. pass either child or builder.

await showAppBottomSheet<void>(
  context: context,
  title: "Saved filters",
  message: "Pin a view to open it faster next time.",
  child: Column(
    mainAxisSize: MainAxisSize.min,
    crossAxisAlignment: CrossAxisAlignment.stretch,
    children: [
      FilledButton(onPressed: () => Navigator.pop(context), child: Text("Pin")),
      OutlinedButton(onPressed: () => Navigator.pop(context), child: Text("Not now")),
    ],
  ),
);

hide the drag handle when the sheet is not meant to feel dismissible by gesture alone, or turn drag/dismiss off entirely.

await showAppBottomSheet<void>(
  context: context,
  title: "Pick a mode",
  showHandle: false,
  isDismissible: false,
  enableDrag: false,
  child: ModeList(),
);

use builder when the body needs the sheet's own context.

await showAppBottomSheet<String>(
  context: context,
  title: "Choose",
  builder: (sheetContext) => ListTile(
    title: const Text("Option A"),
    onTap: () => Navigator.pop(sheetContext, "a"),
  ),
);

example

Future<void> openAppearance(BuildContext context) {
  return showAppBottomSheet<void>(
    context: context,
    title: "Appearance",
    message: "How the app should look on this device.",
    child: Column(
      mainAxisSize: MainAxisSize.min,
      children: [
        for (final mode in ThemeMode.values)
          ListTile(
            title: Text(mode.name),
            onTap: () {
              // apply theme…
              Navigator.pop(context);
            },
          ),
      ],
    ),
  );
}

reference

everything below is here when you need it. you can ship without reading any of it.