flexiblebox 1.0.3 copy "flexiblebox: ^1.0.3" to clipboard
flexiblebox: ^1.0.3 copied to clipboard

Complete CSS Flexbox implementation for Flutter. Features flex grow/shrink, alignment, wrapping, RTL support, absolute positioning, and scrolling.

FlexibleBox #

pub package License: BSD-3-Clause Build Status GitHub stars

A Flutter package that brings CSS Flexbox layout capabilities to your Flutter applications. Create responsive, flexible layouts with ease using familiar flexbox concepts.

Features #

  • Complete Flexbox Implementation: Full CSS flexbox specification support
  • Flexible Sizing: Support for flex grow, shrink, and basis properties
  • Advanced Alignment: Cross-axis and main-axis alignment options
  • Wrapping Support: Multi-line flex layouts with wrap and wrap-reverse
  • RTL Support: Right-to-left language support
  • Absolute Positioning: Position items absolutely within flex containers
  • Scrolling: Built-in scrollable flex containers with 2D scrolling support
  • Sticky Positioning: Sticky items within flex layouts (edge or padded edge)
  • Paint Order Control: Explicit z-order for overlapping elements with shadows
  • Layout Data Builders: Build dynamic UI based on scroll position, overflow, and viewport data
  • Position Type Control: Relative positioning for flex participation or absolute positioning
  • Convenience Widgets: RowBox and ColumnBox for common use cases
  • Custom Spacing: Flexible spacing and padding systems

Installation #

Add the package using Flutter CLI:

flutter pub add flexiblebox

Demo #

View the interactive demo: https://sunarya-thito.github.io/flexbox

Quick Start #

Import the package:

import 'package:flexiblebox/flexiblebox_flutter.dart';
import 'package:flexiblebox/flexiblebox_extensions.dart'; // For convenient extension methods

Create a simple flex layout:

FlexBox(
  direction: FlexDirection.row,
  rowGap: 8.0.spacing,
  children: [
    FlexItem(
      flexGrow: 1.0,
      child: Container(
        color: Colors.red,
        height: 100,
        child: Center(child: Text('Flexible Item')),
      ),
    ),
    FlexItem(
      width: 100.0.size,
      child: Container(
        color: Colors.blue,
        height: 100,
        child: Center(child: Text('Fixed Width')),
      ),
    ),
  ],
)

Why FlexibleBox? #

FlexibleBox provides a different approach to layout compared to Flutter's built-in widgets, offering several advantages for complex, responsive layouts:

CSS Flexbox Specification Compliance #

FlexibleBox implements the complete CSS Flexbox specification, providing familiar layout behavior for developers coming from web development. This includes:

  • True flex-basis calculation: Proper handling of flex grow/shrink with min/max constraints
  • Multi-line wrapping: Full control over line breaking and line alignment
  • Advanced spacing: Separate row and column gaps with space-between, space-around, and space-evenly

Different Layout Philosophy #

FlexibleBox uses a fundamentally different layout approach compared to Flutter's native constraint-based system:

Flutter's Layout System (BoxConstraints)

Flutter uses a "constraints go down, sizes go up" protocol:

  1. Parent passes BoxConstraints (min/max width and height) to children
  2. Each child decides its size within those constraints
  3. Children return their chosen size to the parent
  4. Parent uses returned sizes to position children

This is a single-pass, local decision system where:

  • Each widget only knows about constraints from its immediate parent
  • Children make sizing decisions independently
  • Parent positions children after all sizes are known
  • No child can know the final sizes of its siblings

Example with Flutter's Row:

Row(
  children: [
    Expanded(child: Container()), // Gets remaining space
    Container(width: 100),         // Fixed 100px
  ],
)

The Expanded child doesn't know the other child's size during layout - Flutter's Row manages the space distribution after collecting all sizes.

FlexibleBox's Layout System

FlexibleBox implements a multi-pass CSS Flexbox algorithm:

  1. First Pass - Measurement: Layout all children with loose constraints to determine their intrinsic/preferred sizes (flex-basis)
  2. Second Pass - Flex Resolution: Calculate available space and distribute it among flex items using flex-grow and flex-shrink factors, respecting min/max constraints
  3. Third Pass - Cross-Axis Sizing: Determine cross-axis sizes based on alignment and stretch behavior
  4. Fourth Pass - Positioning: Place all children at their final positions with knowledge of all sizes and spacing

This is a multi-pass, global optimization system where:

  • The container knows all children's sizes before making final decisions
  • Space is distributed according to flex factors after measuring all children
  • Children can be sized relative to viewport, content, or sibling dimensions
  • Proper handling of complex scenarios with multiple constraints
  • Children receive tight constraints during layout: Because the parent has already calculated the exact size each child should be, it passes tight constraints (min == max) to children during the final layout pass. This is different from Flutter's typical loose constraints and ensures precise control over final dimensions.
  • Native 2D scrolling: FlexibleBox supports simultaneous horizontal and vertical scrolling without nested scroll views. The included Scrollbars widget provides unified visual feedback for both scroll directions.

Example with FlexibleBox:

FlexBox(
  direction: FlexDirection.row,
  children: [
    FlexItem(
      flexGrow: 1,
      minWidth: 100.size,
      child: Container(),
    ),
    FlexItem(
      width: 200.size,
      flexShrink: 2,
      child: Container(),
    ),
  ],
)

FlexibleBox measures both children first, calculates total space needed (300px), then distributes available space or shrinkage proportionally according to flex factors while respecting the minWidth constraint - just like CSS Flexbox.

Key Technical Differences

Aspect Flutter (Row/Column) FlexibleBox
Layout passes Single pass Multi-pass (measure → flex → align → position)
Size constraints BoxConstraints (min/max) SizeUnit (fixed, viewport-relative, content-based)
Flex algorithm Simplified flex with MainAxisSize/CrossAxisAlignment Full CSS Flexbox specification
Space distribution Basic Expanded/Flexible widgets Precise flex-grow/flex-shrink with proper constraint handling
Sibling awareness No knowledge of sibling sizes Full knowledge of all children after measurement
Child constraints Typically loose constraints Tight constraints (min == max) during final layout
Wrapping No native support in Row/Column Multi-line with line alignment (align-content)
2D Scrolling Requires nested scroll views Native support with unified scrollbars
Overflow Handled by parent constraints Explicit overflow modes with viewport positioning

This multi-pass approach allows FlexibleBox to handle scenarios that are difficult or impossible with Flutter's single-pass system, such as distributing space proportionally among items with complex size constraints, or positioning elements relative to total content size.

Advanced Features Comparison

FlexibleBox provides sophisticated sizing, positioning, spacing, and alignment options that go far beyond Flutter's native capabilities:

Feature Category Flutter (Row/Column/Stack) FlexibleBox
Sizing Options • Fixed sizes (width/height)
• BoxConstraints (min/max)
• Expanded/Flexible
• Fixed sizes (SizeUnit.fixed)
• Viewport-relative (0.5.relativeSize for 50%)
• Content-relative sizing
• Min/max per item
• Flex grow/shrink with proper constraint handling
Positioning • Stack with Positioned (absolute only)
• Sticky via Slivers (complex, limited contexts)
• No relative positioning context
• Absolute positioning (PositionType.none)
• Relative positioning context (PositionType.relative)
• Sticky positioning (top/left/bottom/right offsets)
• Scroll-aware positioning
Spacing • MainAxisAlignment (limited distribution)
• SizedBox for gaps
• No native gap support
• Row and column gaps (native)
• space-between (even distribution)
• space-around (half space at edges)
• space-evenly (equal space everywhere)
• Flexible padding with viewport units
Alignment • MainAxisAlignment (5 options)
• CrossAxisAlignment (5 options)
• No multi-line alignment
• No align-content
• justifyContent (main-axis, 7 options)
• alignItems (cross-axis, 6 options)
• alignSelf (per-item override)
• alignContent (multi-line, 7 options)
• Stretch alignment
• Full CSS Flexbox spec
Additional Features • Fixed paint order (tree order)
• No layout data access
• Hit testing limited to parent bounds
• paintOrder (explicit z-ordering)
• Layout data builders (scroll, overflow, viewport info)
• Hit testing respects actual painted bounds
• Overflow bounds detection

Key Advantages:

  • Viewport-Relative Sizing: Use 0.5.relativeSize or 0.3.relativeSize to size elements relative to the viewport (50% or 30%), eliminating the need for LayoutBuilder and MediaQuery boilerplate
  • True Sticky Positioning: Elements that scroll normally until reaching an edge, then stick (not possible with Row/Column, requires complex Sliver setup in Flutter)
  • Space Distribution Algorithms: Proper space-between, space-around, and space-evenly that work with wrapping layouts (Flutter's MainAxisAlignment is limited)
  • Per-Item Constraints: Each FlexItem can have its own min/max width/height that integrates with the flex algorithm (Flutter requires manual constraint management)
  • Multi-Line Alignment: Control how wrapped lines distribute within the container with alignContent (no equivalent in Flutter's Wrap)
  • Paint Order Control: Override natural paint order for proper shadow and overlay rendering (impossible in Flutter without restructuring the widget tree)
  • Layout-Aware Building: Access scroll position, overflow bounds, and viewport data to build dynamic, responsive UI (limited to basic constraints in Flutter's LayoutBuilder)

Flutter Layout Limitations #

Flutter's constraint-based system has several inherent limitations that FlexibleBox addresses:

1. No Sibling Size Awareness

In Flutter's single-pass system, children cannot know their siblings' sizes during layout. This makes certain layouts challenging:

Problem:

// Trying to make items equal to the tallest item
Column(
  children: [
    Container(height: 100), // Unknown to siblings
    Container(height: 150), // Unknown to siblings
    Container(height: 120), // Unknown to siblings
  ],
)

You need workarounds like IntrinsicHeight or manual state management.

FlexibleBox Solution:

FlexBox(
  direction: FlexDirection.column,
  alignItems: BoxAlignmentGeometry.stretch, // All items match tallest
  children: [
    FlexItem(child: Container()),
    FlexItem(child: Container()),
    FlexItem(child: Container()),
  ],
)

FlexibleBox knows all children's sizes after measurement and can apply stretch alignment.

2. Complex Flex Distribution

Flutter's Expanded and Flexible widgets handle basic flex scenarios, but struggle with complex constraints:

Problem:

Row(
  children: [
    Flexible(
      flex: 2,
      child: Container(
        constraints: BoxConstraints(minWidth: 200, maxWidth: 300),
        // Flutter may not respect these constraints optimally
      ),
    ),
    Flexible(flex: 1, child: Container()),
  ],
)

Flutter's flex resolution doesn't follow CSS Flexbox rules precisely when constraints conflict.

FlexibleBox Solution:

FlexBox(
  direction: FlexDirection.row,
  children: [
    FlexItem(
      flexGrow: 2,
      flexShrink: 2,
      minWidth: 200.size,
      maxWidth: 300.size,
      child: Container(),
    ),
    FlexItem(flexGrow: 1, flexShrink: 1, child: Container()),
  ],
)

FlexibleBox implements the full CSS Flexbox algorithm with proper constraint handling and shrink factor calculations.

3. Pointer Events Outside Parent Bounds

This is a critical limitation: Flutter does not deliver pointer events (taps, drags, hovers) to child widgets that are positioned outside their parent's paint bounds.

Problem with Flutter's Stack:

Container(
  width: 200,
  height: 200,
  color: Colors.blue,
  child: Stack(
    clipBehavior: Clip.none, // Allows visual overflow
    children: [
      Positioned(
        left: -50, // 50px outside parent bounds
        top: 100,
        child: ElevatedButton(
          onPressed: () => print('Clicked!'),
          child: Text('Button'),
        ),
      ),
    ],
  ),
)

The button is visible (with Clip.none), but the left 50px cannot be clicked because it's outside the parent's 200px width. Flutter's hit testing only considers the parent's bounds, not the child's actual painted area.

FlexibleBox Solution:

Container(
  width: 200,
  height: 200,
  child: FlexBox(
    clipContent: false, // Allows visual and interactive overflow
    children: [
      AbsoluteItem(
        left: (-50).position, // 50px outside parent bounds
        top: 100.position,
        child: ElevatedButton(
          onPressed: () => print('Clicked!'),
          child: Text('Button'),
        ),
      ),
    ],
  ),
)

FlexibleBox respects the child's actual painted bounds for hit testing, meaning:

  • If clipContent: false, the entire button (including the part outside parent bounds) is clickable
  • If clipContent: true, hit testing is clipped to parent bounds (like Flutter's default)
  • You have explicit control over both visual clipping and interaction clipping

Important: Standard Flutter widgets will block pointer events outside their bounds, even when wrapping FlexibleBox. To preserve FlexibleBox's extended hit testing behavior, avoid wrapping it with non-FlexibleBox widgets.

This breaks extended hit testing:

Container(
  // this Container blocks pointer events outside its bounds,
  // so the left 50px of the button will not be clickable
  width: 200,
  height: 200,
  color: Colors.grey,
  child: FlexBox(
    clipContent: false,
    children: [
      AbsoluteItem(
        left: (-50).position, // 50px outside Container bounds
        top: 100.position,
        child: ElevatedButton(
          onPressed: () => print('Clicked!'),
          child: Text('Button'),
        ),
      ),
    ],
  ),
)

The Container's 200×200 bounds will block pointer events to the left 50px of the button, even though FlexBox allows the button to render outside.

This preserves extended hit testing:

Container(
  // this Container blocks pointer events outside its bounds,
  width: 200,
  height: 200,
  color: Colors.grey,
  child: Stack(
    // Stack is 200x200, and also blocks pointer events outside its bounds,
    // but Stack shrinks the FlexBox so it fits within Container,
    // making it able to receive pointer events outside 200x200 area
    // although it is now a little bit smaller visually
    children: [
      Positioned(
        top: 0,
        left: 50,
        right: 0,
        bottom: 0,
        child: FlexBox(
          clipContent: false,
          children: [
            AbsoluteItem(
              left: (-50).position, 
              top: 100.position,
              child: ElevatedButton(
                onPressed: () => print('Clicked!'),
                child: Text('Button'),
              ),
            ),
          ],
        ),
      ),
    ],
  ),
)

By using AbsoluteItem for the background instead of wrapping FlexBox with Container, pointer events work correctly for elements outside the 200×200 area.

This is crucial for:

  • Dropdown menus that extend beyond their trigger button
  • Tooltips that overflow their parent container
  • Floating action buttons positioned at container edges
  • Context menus and popovers
  • Any UI where interactive elements need to overflow their layout bounds

4. Viewport-Relative Sizing

Flutter's constraints are always relative to the immediate parent, making viewport-relative sizing cumbersome:

Problem:

// Need LayoutBuilder and manual calculations
LayoutBuilder(
  builder: (context, constraints) {
    final screenWidth = MediaQuery.of(context).size.width;
    return Container(
      width: screenWidth * 0.5, // 50% of screen width
      child: Text('Half screen width'),
    );
  },
)

Note: Using LayoutBuilder prevents Flutter from computing intrinsic sizes for this widget subtree. Widgets like IntrinsicWidth, IntrinsicHeight, or any parent that queries child intrinsic dimensions will not work correctly with LayoutBuilder in the path, because builders cannot provide intrinsic measurements without actual constraints.

FlexibleBox Solution:

FlexBox(
  children: [
    FlexItem(
      width: 0.5.relativeSize, // 50% of viewport directly
      child: Text('Half screen width'),
    ),
  ],
)

FlexibleBox has built-in viewport awareness with no extra widgets needed.

5. Two-Dimensional Scrolling

Flutter's scrolling widgets (SingleChildScrollView, ListView, CustomScrollView) only support single-axis scrolling. For 2D scrolling, you must nest scroll views, which has several issues:

Problem with Nested ScrollViews:

// Nested scrolling - problematic
SingleChildScrollView(
  scrollDirection: Axis.horizontal,
  child: SingleChildScrollView(
    scrollDirection: Axis.vertical,
    child: Container(
      width: 2000,
      height: 2000,
      // Large content
    ),
  ),
)

Issues with this approach:

  • Ambiguous gesture handling (which scroll view captures the drag?)
  • No unified scrollbar for both directions
  • Difficult to coordinate scroll positions
  • Cannot use diagonal drag gestures effectively

FlexibleBox Solution:

SizedBox(
  width: 400,
  height: 300,
  child: Scrollbars(
    // Unified scrollbar widget supporting both directions
    child: FlexBox(
      horizontalOverflow: LayoutOverflow.hidden, // Enable horizontal scroll with clipping
      verticalOverflow: LayoutOverflow.hidden,   // Enable vertical scroll with clipping
      children: [
        FlexItem(
          width: 2000.size,  // Wide content
          height: 2000.size, // Tall content
          child: YourLargeWidget(),
        ),
      ],
    ),
  ),
)

Advantages:

  • Single scroll context: No nested scroll views, cleaner gesture handling
  • Diagonal scrolling: Users can drag diagonally to scroll in both directions simultaneously
  • Unified scrollbars: The Scrollbars widget shows both horizontal and vertical scrollbars automatically based on overflow
  • Coordinated scrolling: Both axes share the same scroll context and can be controlled programmatically together

Scrollbars Widget Features:

  • Automatically shows/hides based on content overflow
  • Supports both horizontal and vertical scrolling in the same widget
  • Customizable appearance (thumb color, thickness, margins)
  • Interactive dragging on scrollbar thumbs
  • Smooth fade in/out animations
  • Works seamlessly with touch, mouse, and trackpad input

Important Note on Child Building:

Unlike Flutter's ListView, GridView, or other lazy-loading scrolling widgets, FlexibleBox builds all children upfront, even those that are outside the visible viewport. When clipContent: true, children outside the viewport are not painted (not visible), but they are still built and exist in the widget tree.

This is a fundamental difference in approach:

  • Flutter's ListView: Builds children lazily as they scroll into view (optimized for many items)
  • FlexibleBox: Builds all children immediately (optimized for complex layouts with known items)

Implications:

  • Best for: Known, finite number of items with complex flex layouts
  • Best for: Content where all items need to participate in flex calculations
  • ⚠️ Not ideal for: Very long lists with hundreds or thousands of items
  • ⚠️ Not ideal for: Infinite scrolling scenarios where lazy loading is essential

If you have a large number of items (e.g., 100+), consider using Flutter's ListView or GridView instead, or implement custom lazy loading on top of FlexibleBox.

This makes FlexibleBox ideal for:

  • Data tables or grids with a reasonable number of rows/columns
  • Image galleries with a known set of images
  • Maps or canvas-like interfaces with fixed content
  • Spreadsheet-style layouts with defined dimensions
  • Dashboard layouts with multiple panels
  • Any content that naturally overflows in both dimensions but has a finite, known size

6. Wrap Widget Limitations

Flutter's Wrap widget provides basic wrapping functionality, but lacks many flexbox features:

Limitations of Flutter's Wrap:

  1. No Flex Growing/Shrinking: Items in Wrap cannot grow or shrink to fill space

    Wrap(
      children: [
        Container(width: 100, child: Text('Fixed')),
        Container(width: 150, child: Text('Also Fixed')),
        // No equivalent to flex-grow or flex-shrink
      ],
    )
    
  2. No Main-Axis Alignment Per Line: Wrap has alignment but it's global, not per-line

    Wrap(
      alignment: WrapAlignment.spaceBetween, // Applied uniformly
      children: [/* items */],
    )
    

    You cannot have different alignment for different lines or space-between that respects line breaks.

  3. No Cross-Axis Line Alignment: No equivalent to CSS Flexbox's align-content

    Wrap(
      runAlignment: WrapAlignment.start, // Limited line alignment
      // No space-between, space-around, space-evenly for lines
    )
    
  4. No Size Constraints on Items: Cannot set min/max width/height per item within the wrap

    Wrap(
      children: [
        Container(
          constraints: BoxConstraints(minWidth: 100, maxWidth: 200),
          // Works, but doesn't interact with wrap algorithm
        ),
      ],
    )
    

FlexibleBox Solution:

FlexBox(
  direction: FlexDirection.row,
  wrap: FlexWrap.wrap,
  justifyContent: BoxAlignmentBase.spaceBetween, // Per-line space distribution
  alignContent: BoxAlignmentContent.spaceEvenly, // Line distribution
  alignItems: BoxAlignmentGeometry.stretch,      // Stretch alignment
  rowGap: 8.spacing,
  columnGap: 8.spacing,
  children: [
    FlexItem(
      flexGrow: 1,           // Grows to fill space
      flexShrink: 1,         // Shrinks when constrained
      minWidth: 100.size,    // Minimum width constraint
      maxWidth: 300.size,    // Maximum width constraint
      child: Text('Flexible'),
    ),
    FlexItem(
      flexGrow: 2,           // Grows twice as fast
      minWidth: 150.size,
      child: Text('More flexible'),
    ),
    FlexItem(
      width: 120.size,       // Fixed width
      child: Text('Fixed'),
    ),
  ],
)

Key Differences:

Feature Flutter Wrap FlexibleBox (with wrap)
Flex grow/shrink ❌ No ✅ Full flex-grow and flex-shrink support
Per-line alignment ❌ Global only ✅ justify-content applies per line
Line distribution ❌ Basic runAlignment ✅ align-content with space-between, space-around, space-evenly
Size constraints ❌ No interaction with layout ✅ min/max width/height integrated with flex algorithm
Gap control ✅ spacing, runSpacing ✅ rowGap, columnGap (same capability)
Item stretching ❌ No ✅ Cross-axis stretch alignment
Reverse wrap ❌ No ✅ FlexWrap.wrapReverse
Max items per line ❌ No ✅ maxItemsPerLine property
Max lines ❌ No ✅ maxLines property

Example: Responsive Tag List

With Wrap, tags are fixed size:

Wrap(
  spacing: 8,
  children: [
    Chip(label: Text('Flutter')),
    Chip(label: Text('Dart')),
    Chip(label: Text('Mobile Development')),
  ],
)

With FlexibleBox, tags can grow to fill lines efficiently:

FlexBox(
  direction: FlexDirection.row,
  wrap: FlexWrap.wrap,
  justifyContent: BoxAlignmentBase.spaceBetween,
  rowGap: 8.spacing,
  columnGap: 8.spacing,
  children: [
    FlexItem(
      flexGrow: 1,
      minWidth: 80.size,
      child: Chip(label: Text('Flutter')),
    ),
    FlexItem(
      flexGrow: 1,
      minWidth: 80.size,
      child: Chip(label: Text('Dart')),
    ),
    FlexItem(
      flexGrow: 1,
      minWidth: 80.size,
      child: Chip(label: Text('Mobile Development')),
    ),
  ],
)

The FlexibleBox version ensures tags grow proportionally to fill each line while respecting minimum sizes, creating a more polished responsive layout.

7. No Control Over Paint Order

Flutter paints children in the order they appear in the widget tree, which can cause visual issues when children overlap:

Problem with Flutter:

Stack(
  children: [
    Positioned(
      left: 50,
      top: 50,
      child: Container(
        width: 100,
        height: 100,
        decoration: BoxDecoration(
          color: Colors.red,
          boxShadow: [
            BoxShadow(
              color: Colors.black45,
              blurRadius: 20,
              spreadRadius: 5,
            ),
          ],
        ),
      ),
    ),
    Positioned(
      left: 100,
      top: 100,
      child: Container(
        width: 100,
        height: 100,
        color: Colors.blue,
      ),
    ),
  ],
)

In this example, the red container has a shadow. The shadow will paint above the previous sibling (nothing in this case) but will paint below the blue container (next sibling) due to Flutter's natural paint order. This creates an inconsistent visual appearance where the shadow is partially cut off.

FlexibleBox Solution:

FlexBox(
  children: [
    AbsoluteItem(
      left: 50.position,
      top: 50.position,
      paintOrder: 2, // Paint on top
      child: Container(
        width: 100,
        height: 100,
        decoration: BoxDecoration(
          color: Colors.red,
          boxShadow: [
            BoxShadow(
              color: Colors.black45,
              blurRadius: 20,
              spreadRadius: 5,
            ),
          ],
        ),
      ),
    ),
    AbsoluteItem(
      left: 100.position,
      top: 100.position,
      paintOrder: 1, // Paint below
      child: Container(
        width: 100,
        height: 100,
        color: Colors.blue,
      ),
    ),
  ],
)

The paintOrder property allows explicit control over the drawing order:

  • Optional property: If not set, items follow Flutter's natural paint order (tree order)
  • Lower values paint first (appear behind)
  • Higher values paint later (appear in front)
  • Items with the same paintOrder value use tree order as a tiebreaker
  • This ensures shadows and overlapping elements render correctly regardless of tree position

Use Cases:

  • Ensuring shadows always render above or below specific elements
  • Creating layered UI with explicit z-order control
  • Overlapping cards or panels with consistent stacking
  • Tooltips and popovers that should always appear on top

8. Sticky Positioning Not Natively Supported

Flutter has no built-in support for sticky positioning (elements that behave like relative positioning until scrolling, then become fixed within their container).

Note: Flutter does provide sticky-like behavior through SliverAppBar and SliverPersistentHeader within CustomScrollView, but this requires using the sliver architecture which is complex and limited to specific scrolling contexts. It's not a general-purpose sticky positioning solution like CSS's position: sticky.

FlexibleBox Solution:

FlexBox(
  direction: FlexDirection.column,
  verticalOverflow: LayoutOverflow.scroll,
  children: [
    FlexItem(
      top: 0.position,    // Stick to the top edge
      child: Container(
        height: 50,
        color: Colors.blue,
        child: Text('Sticky Header'),
      ),
    ),
    FlexItem(
      height: 1000.size,
      child: Text('Long scrollable content...'),
    ),
  ],
)

When scrolling, the header will scroll normally until it reaches the top edge, then "stick" to that position while the rest of the content scrolls beneath it.

Sticky Positioning Options:

  • top: Sticks to the top edge with specified offset (e.g., 10.position for 10px padding)
  • left: Sticks to the left edge
  • right: Sticks to the right edge
  • bottom: Sticks to the bottom edge
  • Can combine multiple edges (e.g., top: 0.position, right: 0.position)

Position Type Control:

FlexibleBox items have a position property that controls positioning behavior:

  • PositionType.relative (default): Item participates in normal flex layout and can use sticky positioning with top/left/bottom/right offsets
  • PositionType.none: Item is removed from flex flow and positioned absolutely (equivalent to CSS position: absolute)

Use Cases:

  • Sticky table headers that remain visible while scrolling
  • Persistent navigation elements within scrollable sections
  • Floating action buttons that stick to container edges
  • Sidebar elements that follow scroll until reaching boundaries

9. No Layout Data for Dynamic UI

Flutter's builder widgets (like LayoutBuilder) provide basic constraints, but don't expose detailed layout information needed for advanced dynamic UIs.

FlexibleBox Solution - Layout Data Builders:

FlexBox(
  horizontalOverflow: LayoutOverflow.scroll,
  verticalOverflow: LayoutOverflow.scroll,
  children: [
    FlexItem.builder(
      width: 2000.size,
      height: 2000.size,
      builder: (context, box) {
        // Access comprehensive layout data
        return Container(
          color: box.overflowBounds.left < 0
              ? Colors.red.withOpacity(0.3)
              : Colors.transparent,
          child: Column(
            children: [
              Text('Child Size: ${box.width.toStringAsFixed(0)} x ${box.height.toStringAsFixed(0)}'),
              Text('Child Offset: (${box.offsetX.toStringAsFixed(0)}, ${box.offsetY.toStringAsFixed(0)})'),
              Text('Scroll Position: (${box.scrollX.toStringAsFixed(0)}, ${box.scrollY.toStringAsFixed(0)})'),
              Text('Max Scroll: (${box.maxScrollX.toStringAsFixed(0)}, ${box.maxScrollY.toStringAsFixed(0)})'),
              Text('Viewport: ${box.viewportWidth.toStringAsFixed(0)} x ${box.viewportHeight.toStringAsFixed(0)}'),
              Text('Content: ${box.contentWidth.toStringAsFixed(0)} x ${box.contentHeight.toStringAsFixed(0)}'),
              Text('Overflow Left: ${box.overflowBounds.left.toStringAsFixed(0)}'),
              Text('Overflow Right: ${box.overflowBounds.right.toStringAsFixed(0)}'),
              Text('Overflow Top: ${box.overflowBounds.top.toStringAsFixed(0)}'),
              Text('Overflow Bottom: ${box.overflowBounds.bottom.toStringAsFixed(0)}'),
            ],
          ),
        );
      },
    ),
  ],
)

Available Layout Data (LayoutBox):

  • size / width / height: The child's actual rendered size
  • offset / offsetX / offsetY: The child's position relative to the parent
  • scrollX / scrollY: Current scroll offset
  • maxScrollX / maxScrollY: Maximum scrollable distance
  • contentSize / contentWidth / contentHeight: Total size of scrollable content
  • viewportSize / viewportWidth / viewportHeight: Visible viewport size
  • overflowBounds: How many pixels the child is outside the parent viewport
    • left: Pixels overflowing left (negative if visible)
    • right: Pixels overflowing right (positive if outside)
    • top: Pixels overflowing top (negative if visible)
    • bottom: Pixels overflowing bottom (positive if outside)
  • childBounds: The child's bounding rectangle
  • viewportBounds: The viewport's bounding rectangle
  • contentBounds: The content's bounding rectangle (adjusted for scroll)
  • horizontalUserScrollDirection: Current horizontal scroll direction
  • verticalUserScrollDirection: Current vertical scroll direction

Builder Variants:

  • FlexItem.builder: Flex item with layout data
  • AbsoluteItem.builder: Absolutely positioned item with layout data
  • LayoutBoxBuilder: Access layout data anywhere in the tree

Use Cases:

  • Highlight elements when they're partially scrolled out of view
  • Show/hide UI elements based on scroll position
  • Display scroll progress indicators
  • Fade in/out content based on visibility
  • Implement parallax effects based on scroll offset
  • Create interactive scroll-based animations
  • Build custom scrollbar indicators
  • Implement virtual scrolling optimizations based on overflow data

When to Use FlexibleBox vs. Flutter Widgets #

Use FlexibleBox when you need:

  • Precise CSS Flexbox behavior for consistency with web layouts
  • Complex responsive layouts with viewport-relative sizing
  • Multi-line wrapping with sophisticated line alignment
  • Absolute or sticky positioning within scrollable containers
  • Space distribution algorithms (space-between, space-around, space-evenly)
  • Interactive elements that need to overflow parent bounds (dropdowns, tooltips)
  • Two-dimensional scrolling (horizontal and vertical simultaneously)
  • Large content that overflows in multiple directions (tables, grids, canvases)
  • Control over paint order for overlapping elements with shadows or effects
  • Sticky headers or footers within scrollable content
  • Dynamic UI that adapts based on scroll position or overflow state
  • Layout data for scroll-based animations or visibility effects

Use Flutter's Row/Column when:

  • You need simple, straightforward layouts
  • You're using Flutter's standard constraint system throughout your app
  • You don't need CSS Flexbox-specific features

Core Components #

FlexBox #

The main flex container widget that implements the flexbox layout algorithm.

FlexBox(
  direction: FlexDirection.row,               // Layout direction
  wrap: FlexWrap.wrap,                        // Wrapping behavior
  alignItems: BoxAlignmentGeometry.start,     // Cross-axis alignment
  alignContent: BoxAlignmentContent.start,    // Content alignment (for wrapping)
  justifyContent: BoxAlignmentBase.start,     // Main-axis distribution
  rowGap: 8.0.spacing,                        // Spacing between items horizontally
  columnGap: 8.0.spacing,                     // Spacing between items vertically
  children: [                                 // Flex items
    FlexItem(child: Text('Item 1')),
    FlexItem(child: Text('Item 2')),
  ],
)

FlexItem #

Configures individual children within a FlexBox.

FlexItem(
  flexGrow: 1.0,                              // Growth factor
  flexShrink: 0.0,                            // Shrink factor
  width: 200.0.size,                          // Preferred width
  height: 100.0.size,                         // Preferred height
  alignSelf: BoxAlignmentGeometry.start,      // Individual alignment
  paintOrder: 0,                              // Paint order (lower values paint first)
  position: PositionType.relative,            // Positioning context (relative or none)
  top: 10.0.position,                         // Sticky positioning offset (for scrollable containers)
  child: Container(
    color: Colors.blue,
    child: Center(child: Text('Flex Item')),
  ),
)

Key Properties:

  • flexGrow / flexShrink: Control how the item grows/shrinks to fill space
  • width / height: Preferred size (can use viewport-relative units)
  • minWidth / maxWidth / minHeight / maxHeight: Size constraints
  • alignSelf: Override container's alignItems for this item
  • paintOrder: Control the drawing order (lower values paint first/behind)
  • position: Set to PositionType.relative (default) to participate in flex layout, or PositionType.none to become absolutely positioned
  • top / left / bottom / right: Used for sticky positioning within scrollable containers (when position is relative)

Builder Variant:

FlexItem.builder provides access to layout data for building dynamic UI:

FlexItem.builder(
  width: 200.size,
  height: 100.size,
  builder: (context, box) {
    // Access layout information
    final isScrolledOut = box.overflowBounds.top < -50;
    return Container(
      color: isScrolledOut ? Colors.red : Colors.blue,
      child: Text('Scrolled: ${box.scrollY.toInt()}px'),
    );
  },
)

The LayoutBox provides comprehensive layout data including scroll position, overflow bounds, viewport size, content size, and more. See "No Layout Data for Dynamic UI" section above for details.

AbsoluteItem #

For absolutely positioned children within a FlexBox. These items are removed from the normal flex flow and positioned relative to the viewport (or nearest ancestor with PositionType.relative).

AbsoluteItem(
  left: 10.0.position,                         // Left offset from viewport edge
  top: 20.0.position,                          // Top offset from viewport edge
  right: 10.0.position,                        // Right offset from viewport edge
  bottom: 20.0.position,                       // Bottom offset from viewport edge
  width: 100.0.size,                           // Fixed width
  height: 50.0.size,                           // Fixed height
  paintOrder: 10,                              // Paint on top of other elements
  child: Container(
    color: Colors.green,
    child: Center(child: Text('Absolute')),
  ),
)

Key Properties:

  • left / top / right / bottom: Position offsets (can use PositionUnit.scrollOffset for scroll-relative positioning)
  • width / height: Fixed size
  • paintOrder: Control the drawing order (useful for overlapping elements with shadows)

Builder Variant:

AbsoluteItem.builder provides access to layout data:

AbsoluteItem.builder(
  right: 20.position,
  bottom: 20.position,
  builder: (context, box) {
    // Show/hide based on scroll position
    final shouldShow = box.scrollY > 100;
    return AnimatedOpacity(
      opacity: shouldShow ? 1.0 : 0.0,
      duration: Duration(milliseconds: 200),
      child: FloatingActionButton(
        onPressed: () {},
        child: Icon(Icons.arrow_upward),
      ),
    );
  },
)

Sticky FlexItem #

For sticky positioning within scrollable flex containers, use the top, left, bottom, and right properties on FlexItem. These create sticky elements that remain fixed relative to the viewport during scrolling. You must also set verticalOverflow or horizontalOverflow to LayoutOverflow.hidden or LayoutOverflow.scroll on the FlexBox.

// Wrap FlexBox in a SizedBox to constrain its size and enable scrolling
SizedBox(
  height: 300.0, // Fixed height to enable scrolling
  child: FlexBox(
    direction: FlexDirection.column,
    children: [
      FlexItem(
        height: 100.0.size,
        child: Container(
          color: Colors.blue,
          child: Center(child: Text('Normal Item')),
        ),
      ),
      // Sticky header that sticks to the top
      FlexItem(
        top: 0.0.position,    // Stick to top edge
        left: 0.0.position,   // Stick to left edge
        right: 0.0.position,  // Stick to right edge
        height: 50.0.size,
        child: Container(
          color: Colors.red,
          child: Center(child: Text('Sticky Header')),
        ),
      ),
      FlexItem(
        height: 200.0.size,
        child: Container(
          color: Colors.green,
          child: Center(child: Text('Content')),
        ),
      ),
      FlexItem(
        height: 200.0.size,
        child: Container(
          color: Colors.yellow,
          child: Center(child: Text('More Content')),
        ),
      ),
    ],
  ),
)

Scrollable AbsoluteItem #

AbsoluteItem positions elements relative to the viewport bounds, not content bounds. This means bottom: PositionUnit.fixed(10.0) positions the element 10 units from the bottom of the viewport, not the content.

For scroll-aware positioning, use PositionUnit.scrollOffset to create elements that move with scroll:

// Wrap FlexBox in a SizedBox to make it scrollable
SizedBox(
  height: 400.0, // Fixed height to enable scrolling
  child: FlexBox(
    direction: FlexDirection.column,
    children: [
      // Regular content
      FlexItem(
        height: 200.0.size,
        child: Container(
          color: Colors.blue,
          child: Center(child: Text('Content 1')),
        ),
      ),
      FlexItem(
        height: 200.0.size,
        child: Container(
          color: Colors.green,
          child: Center(child: Text('Content 2')),
        ),
      ),
      FlexItem(
        height: 200.0.size,
        child: Container(
          color: Colors.yellow,
          child: Center(child: Text('Content 3')),
        ),
      ),
      
      // Absolute positioned element that stays fixed in viewport
      AbsoluteItem(
        right: 20.0.position,                 // 20px from right viewport edge
        bottom: 20.0.position,                // 20px from bottom viewport edge
        width: 60.0.size,
        height: 60.0.size,
        child: FloatingActionButton(
          onPressed: () {},
          child: Icon(Icons.add),
        ),
      ),
      
      // Element that follows scroll position
      AbsoluteItem(
        left: 10.0.position,
        top: PositionUnit.scrollOffset + 10.0.position, // Moves with scroll
        width: 40.0.size,
        height: 40.0.size,
        child: Container(
          color: Colors.red,
          child: Center(child: Text('Scroll\nIndicator')),
        ),
      ),
    ],
  ),
)

Scrollbars #

The Scrollbars widget provides scrollbar UI for scrollable FlexBox containers. It automatically shows/hides scrollbars based on content overflow and supports both vertical and horizontal scrolling.

Basic Usage

SizedBox(
  width: 400,
  height: 300,
  child: Scrollbars(
    child: FlexBox(
      direction: FlexDirection.column,
      children: [
        for (int i = 0; i < 20; i++)
          FlexItem(
            height: 80.size,
            child: Container(
              margin: EdgeInsets.all(8),
              color: Colors.primaries[i % Colors.primaries.length],
              child: Center(child: Text('Item $i')),
            ),
          ),
      ],
    ),
  ),
)

Customizing Scrollbar Appearance

You can customize the scrollbar appearance using DefaultScrollbar:

Scrollbars(
  verticalScrollbar: DefaultScrollbar(
    thumbDecoration: BoxDecoration(
      color: Colors.blue.withOpacity(0.5),
      borderRadius: BorderRadius.circular(4),
    ),
    thumbActiveDecoration: BoxDecoration(
      color: Colors.blue,
      borderRadius: BorderRadius.circular(4),
    ),
    minThumbLength: 48.0,
    margin: EdgeInsets.all(2),
  ),
  horizontalScrollbar: DefaultScrollbar(
    thumbDecoration: BoxDecoration(
      color: Colors.green.withOpacity(0.5),
      borderRadius: BorderRadius.circular(4),
    ),
  ),
  verticalScrollbarThickness: 12,
  horizontalScrollbarThickness: 12,
  child: FlexBox(
    children: [
      // Your content here
    ],
  ),
)

Convenience Widgets #

RowBox

Horizontal flex layout (equivalent to FlexBox(direction: FlexDirection.row)):

RowBox(
  alignItems: BoxAlignmentGeometry.center,
  justifyContent: BoxAlignmentBase.spaceBetween,
  rowGap: 8.0.spacing,
  children: [
    FlexItem(child: Text('Left')),
    FlexItem(child: Text('Center')),
    FlexItem(child: Text('Right')),
  ],
)

ColumnBox

Vertical flex layout (equivalent to FlexBox(direction: FlexDirection.column)):

ColumnBox(
  alignItems: BoxAlignmentGeometry.stretch,
  justifyContent: BoxAlignmentBase.start,
  columnGap: 12.0.spacing,
  children: [
    FlexItem(child: Text('Top')),
    FlexItem(child: Text('Middle')),
    FlexItem(child: Text('Bottom')),
  ],
)

Extension Methods #

The package provides convenient extension methods on int and double for creating units:

import 'package:flexiblebox/flexiblebox_extensions.dart';

// Size units
100.size              // SizeUnit.fixed(100.0)
50.0.size             // SizeUnit.fixed(50.0)
0.5.relativeSize      // SizeUnit.viewportSize * 0.5 (50% of viewport)

// Position units
10.position           // PositionUnit.fixed(10.0)
20.0.position         // PositionUnit.fixed(20.0)
0.25.relativePosition // PositionUnit.viewportSize * 0.25 (25% of viewport)

// Spacing units
8.spacing             // SpacingUnit.fixed(8.0)
16.0.spacing          // SpacingUnit.fixed(16.0)
0.1.relativeSpacing   // SpacingUnit.viewportSize * 0.1 (10% of viewport)

// Percentage helper
50.percent            // 0.5 (useful for calculations)

These extensions make the code more concise and readable:

// Without extensions
FlexItem(
  width: SizeUnit.fixed(100.0),
  height: SizeUnit.fixed(50.0),
  child: MyWidget(),
)

// With extensions
FlexItem(
  width: 100.size,
  height: 50.size,
  child: MyWidget(),
)

Widget Extensions #

The WidgetExtension provides a fluent, chainable API for configuring widget properties in flexbox layouts. Instead of wrapping widgets in FlexItem or AbsoluteItem, you can use extension methods directly on any widget.

import 'package:flexiblebox/flexiblebox_extensions.dart';

// Fluent API for widget configuration
Container(color: Colors.blue)
  .width(100.size)
  .height(50.size)
  .flexGrow(1)
  .selfAligned(BoxAlignment.center);

// Equivalent to:
FlexItem(
  width: 100.size,
  height: 50.size,
  flexGrow: 1,
  alignSelf: BoxAlignment.center,
  child: Container(color: Colors.blue),
);

Available Extension Methods

Sizing:

  • .width(SizeUnit) - Sets widget width
  • .height(SizeUnit) - Sets widget height
  • .sized({SizeUnit? width, SizeUnit? height}) - Sets both dimensions
  • .minWidth(SizeUnit) / .maxWidth(SizeUnit) - Width constraints
  • .minHeight(SizeUnit) / .maxHeight(SizeUnit) - Height constraints
  • .minSized({...}) / .maxSized({...}) - Combined constraints
  • .constrained({...}) - Comprehensive size constraints
  • .aspectRatio(double) - Maintains aspect ratio

Flex Behavior:

  • .flexGrow(double) - Sets flex grow factor
  • .flexShrink(double) - Sets flex shrink factor

Positioning:

  • .top(PositionUnit) / .left(PositionUnit) - Edge offsets
  • .bottom(PositionUnit) / .right(PositionUnit) - Edge offsets
  • .positioned({...}) - Multiple edge offsets
  • .position(PositionType) - Position type (absolute/relative)

Alignment:

  • .selfAligned(BoxAlignmentGeometry) - Individual alignment

Layout Control:

  • .paintOrder(int) - Z-index stacking order
  • .key(Key) / .id(Object) - Key assignment
  • .asFlexItem - Explicitly wrap as FlexItem
  • .asAbsoluteItem - Explicitly wrap as AbsoluteItem

Chaining Example

Extension methods can be chained for a clean, declarative syntax:

FlexBox(
  direction: FlexDirection.row,
  children: [
    // Fixed-size sidebar
    Container(color: Colors.grey)
      .width(200.size)
      .height(100.percent.relativeSize),
    
    // Flexible content area
    Container(color: Colors.white)
      .flexGrow(1)
      .minWidth(300.size)
      .selfAligned(BoxAlignment.stretch),
    
    // Absolutely positioned overlay
    Icon(Icons.close)
      .asAbsoluteItem
      .positioned(top: 10.position, right: 10.position)
      .paintOrder(100),
  ],
)

Layout Properties #

Direction #

  • FlexDirection.row: Left to right (default)
  • FlexDirection.rowReverse: Right to left
  • FlexDirection.column: Top to bottom
  • FlexDirection.columnReverse: Bottom to top

Wrapping #

  • FlexWrap.none: No wrapping (default)
  • FlexWrap.wrap: Wrap to next line
  • FlexWrap.wrapReverse: Wrap to previous line

Alignment #

Main Axis (justifyContent)

  • BoxAlignmentBase.start: Items at the start
  • BoxAlignmentBase.center: Items centered
  • BoxAlignmentBase.end: Items at the end
  • BoxAlignmentBase.spaceBetween: Space between items
  • BoxAlignmentBase.spaceAround: Space around items
  • BoxAlignmentBase.spaceEvenly: Equal space distribution

Cross Axis (alignItems)

  • BoxAlignmentGeometry.start: Items at cross start
  • BoxAlignmentGeometry.center: Items centered
  • BoxAlignmentGeometry.end: Items at cross end
  • BoxAlignmentGeometry.stretch: Items stretch to fill
  • BoxAlignmentGeometry.baseline: Items aligned by baseline

Content Alignment (alignContent)

  • BoxAlignmentContent.start: Lines at container start
  • BoxAlignmentContent.center: Lines centered in container
  • BoxAlignmentContent.end: Lines at container end
  • BoxAlignmentContent.stretch: Lines stretch to fill container
  • BoxAlignmentContent.spaceBetween: Space between lines
  • BoxAlignmentContent.spaceAround: Space around lines
  • BoxAlignmentContent.spaceEvenly: Equal space distribution

Sizing Units #

SizeUnit

  • 100.size or SizeUnit.fixed(double): Fixed size
  • 100.0.relativeSize or SizeUnit.viewportSize * 100.0.size: Viewport-relative size
  • SizeUnit.minContent: Minimum content size
  • SizeUnit.maxContent: Maximum content size
  • SizeUnit.fitContent: Fit content size
  • SizeUnit.viewportSize: Viewport size

PositionUnit

  • 10.position or PositionUnit.fixed(double): Fixed position
  • 10.0.relativePosition or PositionUnit.viewportSize * 10.0.position: Viewport-relative position
  • PositionUnit.zero: Zero position (equivalent to 0.position)
  • PositionUnit.viewportSize: Full viewport size along the axis
  • PositionUnit.contentSize: Total content size along the axis
  • PositionUnit.childSize([Object? key]): Size of the positioned child element or another child by its key
  • PositionUnit.boxOffset: Offset from the box's natural position
  • PositionUnit.scrollOffset: Current scroll offset
  • PositionUnit.contentOverflow: Amount content overflows the viewport
  • PositionUnit.contentUnderflow: Amount content underflows the viewport
  • PositionUnit.viewportStartBound: Start boundary of the viewport
  • PositionUnit.viewportEndBound: End boundary of the viewport
  • PositionUnit.cross(PositionUnit): Convert passed PositionUnit to cross axis
  • PositionUnit.constrained({required PositionUnit position, PositionUnit min, PositionUnit max}): Position constrained within min/max bounds

SpacingUnit

  • 8.spacing or SpacingUnit.fixed(double): Fixed spacing
  • 8.0.relativeSpacing or SpacingUnit.viewportSize * 8.0.spacing: Viewport-based spacing
  • SpacingUnit.viewportSize: Viewport-based spacing

Math Operations #

All unit types (SizeUnit, SpacingUnit, PositionUnit) support mathematical operations:

// Basic arithmetic
SizeUnit combinedWidth = 100.size + 50.size;
PositionUnit offset = 200.position - 50.position;
SpacingUnit scaled = 10.spacing * 2.0; // Multiply by scalar

// Complex expressions (equivalent to CSS calc())
SizeUnit halfViewport = SizeUnit.viewportSize * 0.5; // 50% of viewport size
SizeUnit responsiveSize = 100.size + SizeUnit.viewportSize * 0.2; // 100px + 20% viewport
PositionUnit centered = PositionUnit.viewportSize * 0.5 - PositionUnit.childSize * 0.5; // Center child

// Negation
SizeUnit negative = -100.size;

// Constraints
PositionUnit clamped = 150.position.clamp(
  min: 0.position,
  max: 300.position,
);

API Reference #

For detailed API documentation, visit the API Reference.

Key classes:

Testing #

The package includes comprehensive test coverage. Run tests with:

flutter test

View the interactive demo:

cd demo
flutter run

Contributing #

We welcome contributions! Please see our Contributing Guide for details.

  1. Fork the repository
  2. Create your feature branch (git checkout -b feature/amazing-feature)
  3. Commit your changes (git commit -m 'Add amazing feature')
  4. Push to the branch (git push origin feature/amazing-feature)
  5. Open a Pull Request

License #

This project is licensed under the BSD-3-Clause license - see the LICENSE file for details.

Issues and Feedback #

Found a problem or have a suggestion? We'd love to hear from you!

Report an issue on GitHub

You can report:

  • Bugs: Incorrect behavior, crashes, or unexpected results
  • Feature Requests: Missing features or new capabilities you'd like to see
  • Documentation Issues: Unclear or incorrect documentation
  • Implementation Concerns: Incorrect CSS Flexbox spec implementation
  • Limitation Concerns: Performance issues or architectural limitations
  • API Improvements: Suggestions for better developer experience
  • Questions: Usage questions or clarification requests

When reporting an issue, please include:

  • A clear description of the problem or request
  • Steps to reproduce (for bugs)
  • Expected vs actual behavior
  • Code samples or screenshots if applicable
  • Flutter and package version information

Made with ❤️ for the Flutter community

2
likes
160
points
200
downloads

Publisher

verified publishersunaryathito.space

Weekly Downloads

Complete CSS Flexbox implementation for Flutter. Features flex grow/shrink, alignment, wrapping, RTL support, absolute positioning, and scrolling.

Repository (GitHub)
View/report issues

Topics

#flexbox #css #layout #two-dimensional-scrolling #flex-wrap

Documentation

API reference

License

BSD-3-Clause (license)

Dependencies

data_widget, flutter

More

Packages that depend on flexiblebox