Overview
IntrinsicHeight is a widget that sizes its child to the child’s intrinsic height.
IntrinsicHeight forces its child to have its intrinsic height. This is useful when you want to ensure that multiple children in a Row have the same height, or when you need to dynamically adjust height based on the child’s content. However, this widget has a high performance cost and should be used carefully.
When to use it?
- When children in a Row need to have the same height
- When height should be determined by the child widget’s content
- When you need to match the heights of widgets with varying content
- When Divider or VerticalDivider needs appropriate height
- When CrossAxisAlignment.stretch doesn’t work as expected
Basic Usage
IntrinsicHeight({
child: Row({
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
Container({
color: 'blue',
width: 100,
child: Text('Short text')
}),
Container({
color: 'red',
width: 100,
child: Text('This is much longer text that will span multiple lines')
})
]
})
})
Props
child
Value: Widget | undefined
The child widget whose size will be adjusted to its intrinsic height.
IntrinsicHeight({
child: Container({
color: 'blue',
child: Text('Height adjusts to content')
})
})
How it Works
IntrinsicHeight works as follows:
- It asks the child widget “What is your minimum height at the given width?”
- It creates constraints using the height responded by the child
- It lays out the child with these constraints
This process requires an additional layout pass, which incurs a performance cost.
Practical Examples
Example 1: Equal Height Cards
const EqualHeightCards = () => {
return IntrinsicHeight({
child: Row({
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
Expanded({
child: Card({
child: Padding({
padding: EdgeInsets.all(16),
child: Column({
children: [
Text('Card 1', {
style: TextStyle({ fontSize: 18, fontWeight: 'bold' })
}),
SizedBox({ height: 8 }),
Text('Short content')
]
})
})
})
}),
SizedBox({ width: 16 }),
Expanded({
child: Card({
child: Padding({
padding: EdgeInsets.all(16),
child: Column({
children: [
Text('Card 2', {
style: TextStyle({ fontSize: 18, fontWeight: 'bold' })
}),
SizedBox({ height: 8 }),
Text('This card has more content so it would naturally be taller. Thanks to IntrinsicHeight, Card 1 will have the same height.')
]
})
})
})
})
]
})
});
};
Example 2: Row with Vertical Divider
const RowWithDivider = () => {
return IntrinsicHeight({
child: Row({
children: [
Expanded({
child: Container({
padding: EdgeInsets.all(16),
child: Column({
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text('Section 1', {
style: TextStyle({ fontWeight: 'bold' })
}),
Text('Content for this section')
]
})
})
}),
VerticalDivider({ width: 1, color: '#E0E0E0' }),
Expanded({
child: Container({
padding: EdgeInsets.all(16),
child: Column({
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text('Section 2', {
style: TextStyle({ fontWeight: 'bold' })
}),
Text('Section with more content'),
Text('Additional line'),
Text('Another line')
]
})
})
})
]
})
});
};
Example 3: Stats Dashboard
const StatsDashboard = () => {
return IntrinsicHeight({
child: Row({
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
Expanded({
child: Container({
padding: EdgeInsets.all(20),
decoration: BoxDecoration({
color: '#F0F0F0',
borderRadius: BorderRadius.circular(8)
}),
child: Column({
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text('1,234', {
style: TextStyle({
fontSize: 32,
fontWeight: 'bold',
color: '#2196F3'
})
}),
SizedBox({ height: 8 }),
Text('Total Users')
]
})
})
}),
SizedBox({ width: 12 }),
Expanded({
child: Container({
padding: EdgeInsets.all(20),
decoration: BoxDecoration({
color: '#F0F0F0',
borderRadius: BorderRadius.circular(8)
}),
child: Column({
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text('89%', {
style: TextStyle({
fontSize: 32,
fontWeight: 'bold',
color: '#4CAF50'
})
}),
SizedBox({ height: 8 }),
Text('Active Users'),
Text('+12% from last week', {
style: TextStyle({
fontSize: 12,
color: '#666'
})
})
]
})
})
})
]
})
});
};
Example 4: Sidebar Menu Item
const SidebarMenuItem = ({ icon, title, subtitle, isSelected }) => {
return IntrinsicHeight({
child: Container({
decoration: BoxDecoration({
color: isSelected ? '#E3F2FD' : 'transparent',
borderRadius: BorderRadius.circular(8)
}),
child: Row({
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
Container({
width: 4,
decoration: BoxDecoration({
color: isSelected ? '#2196F3' : 'transparent',
borderRadius: BorderRadius.only({
topLeft: 8,
bottomLeft: 8
})
})
}),
Expanded({
child: Padding({
padding: EdgeInsets.all(12),
child: Row({
children: [
Icon({
icon,
size: 24,
color: isSelected ? '#2196F3' : '#666'
}),
SizedBox({ width: 12 }),
Expanded({
child: Column({
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(title, {
style: TextStyle({
fontWeight: isSelected ? 'bold' : 'normal',
color: isSelected ? '#2196F3' : '#333'
})
}),
if (subtitle) Text(subtitle, {
style: TextStyle({
fontSize: 12,
color: '#999'
})
})
]
})
})
]
})
})
})
]
})
})
});
};
Example 5: Comparison Table Row
const ComparisonRow = ({ feature, basic, pro, enterprise }) => {
return IntrinsicHeight({
child: Row({
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
Expanded({
flex: 2,
child: Container({
padding: EdgeInsets.all(12),
decoration: BoxDecoration({
color: '#F5F5F5',
border: Border.all({ color: '#E0E0E0' })
}),
child: Text(feature, {
style: TextStyle({ fontWeight: 'bold' })
})
})
}),
Expanded({
child: Container({
padding: EdgeInsets.all(12),
decoration: BoxDecoration({
border: Border.all({ color: '#E0E0E0' })
}),
child: Center({
child: basic ?
Icon({ icon: Icons.check, color: 'green' }) :
Icon({ icon: Icons.close, color: 'red' })
})
})
}),
Expanded({
child: Container({
padding: EdgeInsets.all(12),
decoration: BoxDecoration({
border: Border.all({ color: '#E0E0E0' })
}),
child: Center({
child: pro ?
Icon({ icon: Icons.check, color: 'green' }) :
Icon({ icon: Icons.close, color: 'red' })
})
})
}),
Expanded({
child: Container({
padding: EdgeInsets.all(12),
decoration: BoxDecoration({
border: Border.all({ color: '#E0E0E0' })
}),
child: Center({
child: enterprise ?
Icon({ icon: Icons.check, color: 'green' }) :
Icon({ icon: Icons.close, color: 'red' })
})
})
})
]
})
});
};
Performance Considerations
IntrinsicHeight incurs a performance cost because it requires an additional layout pass:
- O(N²) complexity: Deeply nested IntrinsicHeight widgets become exponentially slower
- Consider alternatives: Try other approaches first when possible
- Caution in scroll views: Be especially careful in ListView or scrollable areas
Alternatives
Consider these alternatives when performance is critical:
- Fixed height: Specify explicit heights when possible
- AspectRatio: When the aspect ratio is constant
- Table widget: For table-style layouts
- Custom RenderObject: For complex layout logic
Important Notes
- IntrinsicHeight has a high performance cost, so use it only when necessary
- Avoid deeply nested IntrinsicHeight widgets
- It doesn’t work with infinite height constraints
- Unexpected results may occur if the child’s intrinsic height is undefined
Related Widgets
- IntrinsicWidth: Sizes to the child’s intrinsic width
- AspectRatio: Maintains aspect ratio
- Table: Table layout
- CustomMultiChildLayout: Complex custom layouts