Skip to content

avoid_wrapping_in_padding

v0.4.0 Warning Fix Widget Replacement

Flags a Padding whose child already takes a padding argument of its own — Container, ListView, GridView, SingleChildScrollView, ReorderableListView, Chip, and any of your own widgets that expose one. The wrapper is a whole extra render object doing what the child would have done for free.

The check is structural, not a fixed list: the rule looks at the child’s constructors and reports if any of them declares a named padding parameter.

Each Padding in the tree is a RenderPadding to lay out and paint. When the child already accepts padding:, moving the value inward removes a level of nesting and a render object, and puts the inset next to the widget it belongs to. The quick fix does the move, carrying the key across if the Padding had one.

See also: Padding | ScrollView.padding

// ListView takes its own padding. Wrapping it insets the whole viewport, so
// the scrollbar and the overscroll glow move inward with the content.
Padding(
padding: EdgeInsets.all(16),
child: ListView(children: items),
);
// The inset now applies to the content; the viewport still fills the space.
ListView(padding: EdgeInsets.all(16), children: items);

Nothing here is hard-coded to Flutter’s widgets. Give a widget a padding parameter and the rule starts reporting Padding around it:

class Panel extends StatelessWidget {
const Panel({super.key, this.padding, required this.child});
final EdgeInsetsGeometry? padding;
final Widget child;
@override
Widget build(BuildContext context) => Container(
color: const Color(0xFFEEEEEE),
padding: padding,
child: child,
);
}
// Don't — Panel declares `padding`, so the wrapper is redundant
Padding(padding: const EdgeInsets.all(8), child: Panel(child: body));
// Do
Panel(padding: const EdgeInsets.all(8), child: body);

Note that a padding parameter your widget then ignores will still make the rule report — it reads the constructor signature, not what build does with the value.

A child that already sets padding is left alone. Merging two insets is a decision, not a rewrite:

// Not reported
Padding(
padding: EdgeInsets.all(8),
child: Container(padding: EdgeInsets.all(4), child: Text('Hello')),
);

A Padding with no child is never reported — there is nothing to move the value into.

Only the immediate child is examined. Padding > Center > ListView is not reported, even though the ListView could still take the inset, because moving it across the Center would change the layout.

This rule is in the opinionated preset, so it is on with preset: opinionated, or by name:

many_lints.yaml
rules:
avoid_wrapping_in_padding: true

To turn it off again:

many_lints.yaml
rules:
avoid_wrapping_in_padding: false

To keep the rule on but skip certain paths, use per-rule exclude.