How to Create a Stack Widget in Flutter: Complete Implementation Guide

To create a Stack widget in Flutter, instantiate the Stack class with a children list, wrap specific children in Positioned widgets for absolute positioning, and configure the alignment, fit, and clipBehavior properties to control layout behavior.

The Stack widget is a fundamental layout primitive in the Flutter framework that enables overlapping UI elements. According to the flutter/flutter source code, this widget is defined in packages/flutter/lib/src/widgets/basic.dart and delegates its rendering logic to RenderStack implemented in packages/flutter/lib/src/rendering/stack.dart. Understanding how to create a Stack widget in Flutter allows you to build sophisticated interfaces such as image overlays, badge systems, and custom floating action elements.

Understanding the Stack Widget Architecture

The Stack class extends MultiChildRenderObjectWidget, which means it manages multiple child widgets through a dedicated render object. In packages/flutter/lib/src/widgets/basic.dart, the Stack widget overrides the createRenderObject method to instantiate a RenderStack instance. This render object, defined in packages/flutter/lib/src/rendering/stack.dart, maintains a list of StackParentData objects that store positioning constraints and alignment data for each child.

During the layout phase, RenderStack measures each child and computes offsets based on either the stack’s alignment property or the constraints provided by Positioned wrappers. The painting phase iterates through children in order, calling paintChild with the computed offsets, which creates the overlapping visual effect.

Core Stack Properties and Parameters

The public API in packages/flutter/lib/src/widgets/basic.dart exposes several critical properties that control how the Stack widget sizes and positions its children:

alignment

Determines the default position of children that are not wrapped in a Positioned widget. The default value is AlignmentDirectional.topStart, which positions non-positioned children in the top-left corner (or top-right in right-to-left locales).

fit

Controls how the stack sizes itself relative to its children. StackFit.loose (default) allows the stack to size itself to the largest non-positioned child, while StackFit.expand forces the stack to fill all available space from its parent.

clipBehavior

Replaces the deprecated overflow property and defines how children that exceed the stack’s bounds are clipped. Use Clip.hardEdge to trim overflowing content or Clip.none to allow overflow.

children

The list of widgets to display. Children appear in paint order, meaning the last widget in the list appears on top of previous widgets.

Positioning Children with the Positioned Widget

When you need precise control over a child’s placement, wrap it in a Positioned widget. This widget allows you to specify top, right, bottom, and left insets relative to the stack’s edges. If you provide both left and right (or top and bottom), the child’s width (or height) is constrained to fill the available space. Children without a Positioned wrapper are aligned according to the stack’s alignment property and sized based on the fit property.

Practical Code Examples

Basic Stack with Centered Children

Stack(
  alignment: Alignment.center,
  children: <Widget>[
    Container(
      width: 200,
      height: 200,
      color: Colors.blue,
    ),
    Container(
      width: 100,
      height: 100,
      color: Colors.red,
    ),
    const Text(
      'On top',
      style: TextStyle(color: Colors.white, fontSize: 24),
    ),
  ],
);

The blue square renders first, the red square appears centered on top, and the text displays above both because it is the last child in the list.

Using Positioned to Anchor Widgets

Stack(
  children: <Widget>[
    const Image.network('https://example.com/background.jpg'),
    const Positioned(
      top: 16,
      right: 16,
      child: Icon(Icons.favorite, color: Colors.pink, size: 32),
    ),
    const Positioned(
      bottom: 0,
      left: 0,
      right: 0,
      child: ColoredBox(
        color: Colors.black54,
        child: Padding(
          padding: EdgeInsets.all(8.0),
          child: Text(
            'Caption goes here',
            style: TextStyle(color: Colors.white),
            textAlign: TextAlign.center,
          ),
        ),
      ),
    ),
  ],
);

The Icon anchors to the top-right corner using explicit insets, while the caption spans the full width at the bottom by specifying left: 0 and right: 0.

Controlling Stack Size with fit

SizedBox(
  width: 150,
  height: 150,
  child: Stack(
    fit: StackFit.expand,
    children: <Widget>[
      Container(color: Colors.green),
      const Align(
        alignment: Alignment.bottomRight,
        child: Icon(Icons.star, size: 40, color: Colors.yellow),
      ),
    ],
  ),
);

With fit: StackFit.expand, the green container fills the entire SizedBox area, and the star icon aligns to the bottom-right corner using the Align widget.

Preventing Overflow with clipBehavior

Stack(
  clipBehavior: Clip.hardEdge,
  children: [
    Container(
      width: 100,
      height: 100,
      color: Colors.orange,
    ),
    Positioned(
      top: -20,
      left: -20,
      child: Container(
        width: 50,
        height: 50,
        color: Colors.purple,
      ),
    ),
  ],
);

The purple square would normally overflow the orange container’s bounds, but Clip.hardEdge trims the child at the stack’s boundary.

Summary

  • Instantiate Stack with a children list to create overlapping layouts in packages/flutter/lib/src/widgets/basic.dart.
  • Use Positioned widgets to anchor children to specific edges using top, right, bottom, and left insets.
  • Control sizing with the fit property: StackFit.loose for natural sizing or StackFit.expand to fill available space.
  • Manage overflow using clipBehavior instead of the deprecated overflow property.
  • Understand the render pipeline: Stack creates a RenderStack that uses StackParentData to compute layout offsets and painting order.

Frequently Asked Questions

How does Stack position children without a Positioned widget?

Children that are not wrapped in Positioned are positioned according to the stack’s alignment property, defaulting to AlignmentDirectional.topStart. These children respect the fit property to determine their size within the stack’s constraints.

What is the difference between StackFit.loose and StackFit.expand?

StackFit.loose allows the stack to size itself to the largest non-positioned child, while StackFit.expand forces the stack to fill all available space from its parent, making non-positioned children expand to fill the stack’s dimensions.

How do I prevent overflow errors in a Stack?

Set the clipBehavior property to Clip.hardEdge or Clip.antiAlias to clip children that extend beyond the stack’s bounds. If you need to detect overflow for debugging, you can temporarily set it to Clip.none, but you should handle the overflow properly for production code.

Can I use Stack inside a scrolling widget like ListView?

Yes, but you must constrain the Stack’s height explicitly because ListView provides unbounded constraints in the scroll direction. Wrap the Stack in a SizedBox or Container with a fixed height, or use Positioned children to give the stack a defined size, otherwise you will encounter layout errors.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →