overflow_guard

Catch RenderFlex overflow across many device sizes automatically — in your widget tests / CI, or live at runtime.

device_preview lets you look at your app on other devices by hand. overflow_guard checks for you and fails the test when a screen overflows on any size — so a "breaks on small phones" bug is caught before you ship it, not after a user hits it.

Install

Add it to your dev_dependencies (it is only needed for tests):

dev_dependencies:
  overflow_guard: ^0.2.1

Then run flutter pub get.

Test your screens in 3 steps

1. Create a test filetest/layout_test.dart:

import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:overflow_guard/testing.dart';

import 'package:your_app/checkout_screen.dart';

void main() {
  testWidgets('Checkout fits every device size', (tester) async {
    final report = await checkLayout(
      tester,
      const CheckoutScreen(),
      devices: DeviceSize.all, // small phone -> large tablet
    );

    expectNoOverflow(report); // fails with an exact per-device report
  });
}

2. Run it:

flutter test

3. Read the result. If a screen overflows you get an exact table:

LayoutReport: 2 of 7 device sizes overflowed.
  [PASS] Standard phone (390x844)
  [FAIL] Small phone (320x568): 24.0px on the right
  [FAIL] Foldable (narrow) (280x653): 64.0px on the right
  ...

Now you know the screen, the device size, the edge, and the exact pixels — before shipping.

Choosing device sizes

DeviceSize.common   // 5 everyday sizes: small -> large phone + a tablet
DeviceSize.all      // 7 sizes incl. narrow foldable + large tablet (strictest)

// Or your own:
await checkLayout(tester, const HomeScreen(), devices: const [
  DeviceSize.smallPhone,
  DeviceSize('Company kiosk', 1080, 1920, pixelRatio: 1),
]);

Catch more: large fonts and async screens

Two common overflow causes a default check misses:

await checkLayout(
  tester,
  const ProfileScreen(),
  devices: DeviceSize.all,
  textScales: const [1.0, 1.3, 2.0], // large-font accessibility users
  settle: true,                      // wait for async/loading content
);

textScales re-runs each device at those font scales (a top real-world cause of overflow). settle calls pumpAndSettle so a screen that loads data renders its real content before the check instead of a spinner.

Runtime detection (optional)

You can also watch for overflow live while the app runs:

import 'package:overflow_guard/overflow_guard.dart';

final recorder = OverflowRecorder()..start();
// ... render UI ...
if (recorder.hasOverflow) {
  debugPrint(recorder.issues.toString()); // e.g. [24.0px on the right]
}

How it works

Flutter reports overflow through FlutterError.onError. OverflowRecorder temporarily intercepts that handler, keeps overflow messages, and forwards all other errors untouched. checkLayout drives the widget test's fake screen to each DeviceSize (with a fresh render tree per size, so nothing is de-duplicated) and records what overflows.

API at a glance

Symbol Import Use
checkLayout(tester, screen, {devices}) testing.dart Run the multi-device check in a widget test
expectNoOverflow(report) testing.dart Fail the test if anything overflowed
LayoutReport either hasOverflow, failures, describe()
DeviceSize either Size presets + custom sizes
OverflowRecorder overflow_guard.dart Live runtime detection

Libraries

overflow_guard
overflow_guard -- runtime library.
testing
overflow_guard -- test-time library.