Widgets Nesting Level (WNL)
Widgets nesting level is a quantitative metrics that measures the maximum number of nested widgets in every method that returns a widget (e.g. build).
This metric does not count SizedBox widgets.
Why Be Cautious
High widgets nesting level can lead to:
- Reduced Readability: Deep nesting makes the UI code harder to read and follow.
- Error-Proneness: Changes in a deeply nested structure are more error-prone.
How to Address High Widgets Nesting Level?
First, review the widget tree for potential simplifications. For example, avoid having Row or Column with only one child as in such cases they can be replaced with other widgets.
Overall, try extracting custom widgets that encapsulate some part of the UI. While doing so also pay attention to the extracted code. Usually, during that process you will find multiple places with the similar code that can be replaced with the newly extracted widget.
Config Example
dcm:
metrics:
widgets-nesting-level:
threshold: 10
To set multiple threshold or other common config options, refer to the Configuring Metrics page.
Example
To view what contributes to the metric value, generate an HTML report.
❌ Bad: High Widgets Nesting Level
// WNL: 7
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Example Page'),
),
body: Padding(
padding: const EdgeInsets.all(8.0),
child: Column(
children: [
Container(
padding: EdgeInsets.all(8.0),
decoration: BoxDecoration(
color: Colors.grey[200],
borderRadius: BorderRadius.circular(8.0),
),
child: Row(
children: [
Icon(Icons.info),
SizedBox(width: 5),
Expanded(
child: Text(
'Welcome to the example page!',
style: TextStyle(fontSize: 16),
),
),
],
),
),
SizedBox(height: 10),
Row(
children: [
Icon(Icons.warning),
SizedBox(width: 5),
Text('Warning message here'),
],
),
],
),
),
);
}
✅ Good: Low Widgets Nesting Level
// WNL: 4
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text('Example Page')),
body: Padding(
padding: const EdgeInsets.all(8.0),
child: Column(
spacing: 10,
children: [
InfoBox(text: 'Welcome to the example page!'),
IconTextRow(icon: Icons.warning, label: 'Warning message here'),
],
),
),
);
}
class InfoBox extends StatelessWidget {
final String text;
InfoBox({required this.text});
// WNL: 4
Widget build(BuildContext context) {
return Container(
padding: EdgeInsets.all(8.0),
decoration: BoxDecoration(
color: Colors.grey[200],
borderRadius: BorderRadius.circular(8.0),
),
child: Row(
children: [
Icon(Icons.info),
SizedBox(width: 5),
Expanded(
child: Text(text, style: TextStyle(fontSize: 16)),
),
],
),
);
}
}
class IconTextRow extends StatelessWidget {
final IconData icon;
final String label;
IconTextRow({required this.icon, required this.label});
// WNL: 2
Widget build(BuildContext context) {
return Row(
children: [
Icon(icon),
SizedBox(width: 5),
Text(label),
],
);
}
}