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:

  1. It asks the child widget “What is your minimum height at the given width?”
  2. It creates constraints using the height responded by the child
  3. 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:

  1. O(N²) complexity: Deeply nested IntrinsicHeight widgets become exponentially slower
  2. Consider alternatives: Try other approaches first when possible
  3. Caution in scroll views: Be especially careful in ListView or scrollable areas

Alternatives

Consider these alternatives when performance is critical:

  1. Fixed height: Specify explicit heights when possible
  2. AspectRatio: When the aspect ratio is constant
  3. Table widget: For table-style layouts
  4. 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
  • IntrinsicWidth: Sizes to the child’s intrinsic width
  • AspectRatio: Maintains aspect ratio
  • Table: Table layout
  • CustomMultiChildLayout: Complex custom layouts