flutter-layout

Build responsive Flutter layouts by composing widgets, managing constraints, and adapting to screen sizes. Provides a decision tree for selecting the right base layout widget (Row, Column, Stack, ListView, GridView, CustomScrollView) based on content dimensionality, overlap, scrolling, and responsiveness needs Enforces Flutter's core constraint system: constraints flow down, sizes flow up, parents set position; includes ConstrainedBox patterns for forcing specific dimensions Implements adaptive layouts using LayoutBuilder to branch UI logic based on available width, supporting mobile-to-tablet transitions Covers flex layout composition with Expanded and Flexible widgets for managing child sizing in Rows and Columns, plus fixes for unbounded constraint errors in scrollable contexts

INSTALLATION
npx skills add https://github.com/flutter/skills --skill flutter-layout
Run in your project or agent environment. Adjust flags if your CLI version differs.

SKILL.md

$2a

-

Apply the Golden Rule of Constraints

Enforce Flutter's core layout rule: Constraints go down. Sizes go up. Parent sets position.

When a widget requires a specific size, ensure its parent allows it. Use ConstrainedBox to inject specific constraints, but remember it only adds to the parent's constraints.

// Example: Forcing a specific size within a flexible parent

Center(

  child: ConstrainedBox(

    constraints: const BoxConstraints(

      minWidth: 70,

      minHeight: 70,

      maxWidth: 150,

      maxHeight: 150,

    ),

    child: Container(

      color: Colors.blue,

      width: 1000, // Will be constrained to 150 (max)

      height: 10,  // Will be constrained to 70 (min)

    ),

  ),

)

-

Implement Adaptive Layouts

For screens that must support both mobile and tablet/desktop form factors, implement a LayoutBuilder to branch the UI logic based on available width.

class AdaptiveScreen extends StatelessWidget {

  const AdaptiveScreen({super.key});

  @override

  Widget build(BuildContext context) {

    return Scaffold(

      body: SafeArea(

        child: LayoutBuilder(

          builder: (context, constraints) {

            if (constraints.maxWidth > 600) {

              return _buildWideLayout();

            } else {

              return _buildNarrowLayout();

            }

          },

        ),

      ),

    );

  }

  Widget _buildWideLayout() {

    return Row(

      children: [

        const SizedBox(width: 250, child: Placeholder()), // Sidebar

        Container(width: 1, color: Colors.grey), // Divider

        const Expanded(child: Placeholder()), // Main Content

      ],

    );

  }

  Widget _buildNarrowLayout() {

    return const Column(

      children: [

        Expanded(child: Placeholder()), // Main Content

      ],

    );

  }

}

-

Compose Flex Layouts (Rows and Columns)

When using Row or Column, manage child sizing using Expanded (forces child to fill available space) or Flexible (allows child to be smaller than available space).

Row(

  mainAxisAlignment: MainAxisAlignment.spaceEvenly,

  crossAxisAlignment: CrossAxisAlignment.center,

  children: [

    const Icon(Icons.star),

    Expanded(

      flex: 2,

      child: Container(color: Colors.red, height: 50),

    ),

    Flexible(

      flex: 1,

      child: Container(color: Colors.blue, height: 50),

    ),

  ],

)

-

Gather Context

STOP AND ASK THE USER: "What are the target devices (e.g., mobile, tablet, web) and specific breakpoint widths required for this layout?"

-

Validate-and-Fix: Handle Unbounded Constraints

Verify that no Expanded or Flexible widgets are placed inside unbounded parents (like ListView or SingleChildScrollView). If a RenderFlex overflow occurs, implement the following fix:

// INCORRECT: Expanded inside a scrollable view causes unbounded height errors.

// SingleChildScrollView(child: Column(children: [Expanded(child: Container())]))

// CORRECT: Use a bounded height or remove Expanded.

// Alternatively, use CustomScrollView with SliverFillRemaining:

CustomScrollView(

  slivers: [

    SliverToBoxAdapter(child: HeaderWidget()),

    SliverFillRemaining(

      hasScrollBody: false,

      child: ExpandedContentWidget(),

    ),

  ],

)

Constraints

  • Always wrap top-level screen content in a SafeArea to prevent overlap with system UI.
  • Never place an Expanded or Flexible widget inside a parent that provides unbounded constraints (e.g., SingleChildScrollView, ListView, or Row inside a horizontally scrolling view).
  • Do not use Container solely for padding; use the Padding widget for better performance.
  • Assume the user is using Material 3 (useMaterial3: true is default).
BrowserAct

Let your agent run on any real-world website

Bypass CAPTCHA & anti-bot for free. Start local, scale to cloud.

Explore BrowserAct Skills →

Stop writing automation&scrapers

Install the CLI. Run your first Skill in 30 seconds. Scale when you're ready.

Start free
free · no credit card