Skip to Content

HStack

A horizontal stack layout component that arranges its children horizontally with configurable spacing and alignment.

Overview

HStack provides horizontal layout capabilities using a custom RenderBox implementation. It demonstrates how Flutter’s layout system works under the hood, including support for flexible children via HCustomFlexible and HCustomExpanded.

Primitives Used: Custom RenderBox, CustomMultiChildLayout, ParentDataWidget

HStack ShowcaseOpen in new tab ↗

Basic Usage

import 'package:primitive_ui/primitive_ui.dart'; HStack( spacing: 16.0, children: [ Text('Fixed Width'), HCustomExpanded( child: Container(color: Colors.blue), ), Text('Fixed Width'), ], )

API Reference

Constructor

HStack({ Key? key, required List<Widget> children, double spacing = 0.0, CrossAxisAlignment crossAxisAlignment = CrossAxisAlignment.start, MainAxisAlignment mainAxisAlignment = MainAxisAlignment.start, MainAxisSize mainAxisSize = MainAxisSize.max, })

Parameters

ParameterTypeRequiredDefaultDescription
childrenList<Widget>The widgets to display in the horizontal stack
spacingdouble0.0Horizontal spacing between children (must be >= 0)
crossAxisAlignmentCrossAxisAlignmentCrossAxisAlignment.startHow to align children vertically
mainAxisAlignmentMainAxisAlignmentMainAxisAlignment.startHow to align children horizontally
mainAxisSizeMainAxisSizeMainAxisSize.maxWhether to take maximum or minimum horizontal space

HCustomFlexible & HCustomExpanded

Wrap children in these widgets to control their flex behavior.

HCustomFlexible

HCustomFlexible({ Key? key, int flex = 1, FlexFit fit = FlexFit.loose, required Widget child, })

HCustomExpanded

Shortcut for HCustomFlexible(fit: FlexFit.tight).

HCustomExpanded({ Key? key, int flex = 1, required Widget child, })

Examples

Different Alignments

HStack( crossAxisAlignment: CrossAxisAlignment.start, spacing: 8.0, children: [ Container(width: 50, height: 100, color: Colors.red), Container(width: 50, height: 150, color: Colors.green), Container(width: 50, height: 80, color: Colors.blue), ], )

Flexible Layouts

// Fills available horizontal space HStack( children: [ Container(width: 50, color: Colors.red), HCustomExpanded( child: Container(color: Colors.blue), // Takes remaining space ), Container(width: 50, color: Colors.green), ], )

Main Axis Alignment

HStack( mainAxisAlignment: MainAxisAlignment.start, spacing: 8.0, children: [ Container(width: 50, height: 50, color: Colors.red), Container(width: 50, height: 50, color: Colors.green), Container(width: 50, height: 50, color: Colors.blue), ], )

Toolbar Layout

PrimitiveCard( child: HStack( spacing: 16.0, crossAxisAlignment: CrossAxisAlignment.center, mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Text( 'Dashboard', style: TextStyle(fontSize: 20, fontWeight: FontWeight.bold), ), HStack( spacing: 8.0, children: [ IconButton(icon: Icon(Icons.search), onPressed: () {}), IconButton(icon: Icon(Icons.notifications), onPressed: () {}), CircleAvatar(child: Text('U')), ], ), ], ), )

Implementation Details

Layout Algorithm

The HStack layout process has been upgraded to support two-pass layout for flex children:

  1. Pass 1 (Fixed Children): Measure all non-flex children.

    if (flex == 0) { child.layout(...); totalNonFlexWidth += child.size.width; }
  2. Calculate Free Space: Determine space available for flex children.

    freeSpace = availableWidth - totalNonFlexWidth - totalSpacing;
  3. Pass 2 (Flex Children): Measure flex children using allocated space.

    childWidth = (freeSpace * flex) / totalFlex; child.layout(constraints.tighten(width: childWidth));
  4. Positioning: Place all children in sequence.

RTL Support

HStack respects text direction for horizontal positioning:

if (textDirection == TextDirection.rtl) { currentX = width - leadingSpace; // ... currentX -= child.size.width; // ... currentX -= betweenSpace; } else { currentX = leadingSpace; // ... currentX += child.size.width + betweenSpace; }

Intrinsic Dimensions

HStack implements all intrinsic dimension methods:

  • computeMinIntrinsicWidth: Sum of children’s min widths + spacing
  • computeMaxIntrinsicWidth: Sum of children’s max widths + spacing
  • computeMinIntrinsicHeight: Maximum of children’s min heights
  • computeMaxIntrinsicHeight: Maximum of children’s max heights

Common Patterns

Disabled State

// This is an example from PrimitiveToggleSwitch. Replace with relevant HStack example. bool _isDisabled = true; HStack( children: [ Text('Item 1'), Container(width: 20, height: 20, color: Colors.grey), Text('Item 2'), ], )

Differences from Row

FeatureHStackRow
Flexible/Expanded✅ Supported (via HCustomFlexible)✅ Supported
Baseline alignment❌ Not supported✅ Supported
Text direction✅ Supported✅ Supported
Intrinsic sizing✅ Implemented✅ Implemented
PerformanceGood for simple layoutsOptimized for all cases

Best Practices

Use HStack When:

  • You need simple horizontal layouts
  • Learning how layout systems work
  • Building educational projects
  • Spacing between children is uniform
  • You need precise control over spacing (using spacing param)

Use Row Instead When:

  • You need baseline alignment
  • Performance is critical with many children
  • You rely on standard Flutter widgets that expect Row
  • VStack - For vertical layouts
  • ZStack - For layered layouts

Source Code

View the complete implementation in the GitHub repository .

Last updated on