responsive_size_builder
Responsive Flutter layout builders for screen-wide breakpoints, local parent constraints, shared responsive values, orientation variants, granular window tiers, and Material 3 window size classes.
Use it when a Flutter UI needs explicit responsive decisions without scattering
MediaQuery, LayoutBuilder, and breakpoint conditionals through the widget
tree.
This package is also LLM-friendly by design. It is intentionally used in LLM
code-writing systems where generated Flutter code needs predictable responsive
ownership, clear API choices, and a small set of patterns that are easy to
inspect. The package includes an optional LLM usage skill at
skills/topical-responsive-size-builder
so coding agents can learn the intended API selection rules before writing UI.
Contents
- Features
- LLM-Friendly Responsive UI
- Installation
- Mental Model
- API Map
- Breakpoints And Fallbacks
- Screen-Owned Layout
- Screen-Owned Values
- Local Parent Constraints
- Local Layout Helpers
- Shared Responsive Config
- Material 3 Window Classes
- Orientation And Shortest Side
- Architecture And State
- Testing Responsive UI
- LLM Usage Skill
- Example App
- License
Features
- Screen-wide builders for route shells, page layouts, and app-level structure.
- Constraint-driven builders for reusable widgets, cards, dialogs, panes, and other local layout regions.
- Value builders for padding, spacing, column counts, maximum widths, icon sizes, density, and other scalar layout decisions.
- Shared responsive values through
ScreenSizeWithValueandResponsiveValue. - Standard 5-tier breakpoints, granular breakpoint tiers, orientation variants, and shortest-side classification.
- Material 3 window size classes and adaptive layout constants through
MaterialResponsiveSize. - Local helpers for responsive grids and section rows.
- A checked-in LLM usage skill and focused reference docs.
LLM-Friendly Responsive UI
responsive_size_builder is a normal Flutter package for human-written apps. It
is also shaped to work well in LLM-assisted coding workflows.
Responsive bugs in generated UI often come from unclear ownership: a component branches on full screen width when its parent pane is narrow, a router is created inside a breakpoint branch, or a widget tree is rebuilt when only a padding value changed. This package keeps those choices visible:
- screen APIs mean the full app window owns the decision
- layout APIs mean the parent constraints own the decision
- value builders mean the widget structure stays the same
- shared responsive values mean a subtree needs one coherent layout contract
- Material APIs mean Material 3 window classes own the responsive model
The included skill is for coding assistants that support local skill files. If
your workflow uses an LLM to write Flutter, point it at
skills/topical-responsive-size-builder/SKILL.md
or paste the relevant README section into the coding context.
LLM support is optional. The public Dart APIs are the package contract, and the README is written to be usable as the main human-facing guide.
Installation
dependencies:
responsive_size_builder: ^0.1.2
Then import the package:
import 'package:responsive_size_builder/responsive_size_builder.dart';
Mental Model
Choose the responsive owner first.
The owner is the smallest boundary that controls the width and state affected by the responsive decision. Once the owner is clear, the API choice is usually straightforward.
Use screen-wide APIs when the full app window owns the decision:
- route shells
- app navigation chrome
- page-level list vs grid structure
- master-detail shells
- subtrees that should all share one
MediaQuerybreakpoint
Use local constraint APIs when a parent container owns the decision:
- reusable widgets
- cards in narrow panes
- dialogs and sheets
- side panels
- form sections
- any component whose available width can differ from the screen width
Use value APIs when the widget tree stays the same and only a value changes:
- padding
- spacing
- column count
- icon size
- content max width
- density
- pane count
Use shared responsive values when several descendants need the same resolved layout config:
LayoutConfig(columns, padding, showSideMenu)- pane count and pane spacing
- navigation mode
- density and sizing policy
Use Material APIs when Material 3 adaptive layout guidance is the design model.
API Map
| Need | Use | Why |
|---|---|---|
| Wrap a screen-owned route, page, or shell | ScreenSize |
Provides a screen breakpoint from MediaQuery width. |
| Branch full-screen widget structure | ScreenWidgetBuilder |
Swaps page or shell structure by screen breakpoint. |
| Resolve a full-screen scalar value | ScreenValueBuilder |
Changes one value while keeping the widget structure stable. |
| Share one responsive config through a subtree | ScreenSizeWithValue |
Provides both breakpoint data and a typed responsive value. |
| Branch with shared config available | ScreenWithValueWidgetBuilder |
Lets branch builders read the shared responsive value. |
| Resolve a value inside a shared-config subtree | ScreenWithValueValueBuilder |
Keeps value resolution tied to ScreenSizeWithValue. |
| Branch by parent constraints | LayoutWidgetBuilder |
Uses local LayoutBuilder constraints instead of screen width. |
| Resolve a local scalar value | LayoutValueBuilder |
Changes one value based on parent constraints. |
| Flow repeated children into columns | ResponsiveGrid |
Calculates equal-width columns from available width. |
| Row sections when they fit, stack when narrow | ResponsiveSectionRow |
Keeps sections side by side only when each section can fit. |
| Use Material 3 window classes | MaterialResponsiveSize |
Provides MaterialWindowSizeClass and MaterialResponsiveValues. |
| Use custom product breakpoints | Breakpoints or BreakpointsGranular |
Keeps thresholds at the boundary that owns the behavior. |
Standard APIs use LayoutSize:
extraLargelargemediumsmallextraSmall
Granular APIs use LayoutSizeGranular for compact, standard, jumbo, and
ultra-wide tiers, with tiny below the smallest configured threshold.
Breakpoints And Fallbacks
The standard breakpoint defaults are:
const Breakpoints(
small: 200,
medium: 600,
large: 950,
extraLarge: 1200,
);
Breakpoint values are minimum logical widths. extraSmall is the fallback below
small.
Custom breakpoints should live at the same boundary that owns the responsive behavior:
ScreenSize<LayoutSize>(
breakpoints: const Breakpoints(
small: 600,
medium: 950,
large: 1200,
extraLarge: 1400,
),
child: const OrdersShell(),
)
Builders and responsive values accept sparse breakpoint entries. If the current breakpoint has no explicit value, the package resolves through the configured value map until it finds a provided value.
ScreenWidgetBuilder(
extraSmall: (context, data) => const CompactPage(),
large: (context, data) => const WidePage(),
)
Provide entries where behavior changes. Repeating identical values at every breakpoint usually makes the responsive contract harder to read.
Use granular APIs when five buckets are too coarse:
ScreenSize<LayoutSizeGranular>(
breakpoints: BreakpointsGranular.defaultBreakpoints,
child: ScreenWidgetBuilderGranular(
compactSmall: (context, data) => const CompactShell(),
standardNormal: (context, data) => const StandardShell(),
jumboSmall: (context, data) => const JumboShell(),
),
)
Screen-Owned Layout
Use ScreenSize and ScreenWidgetBuilder when screen width changes the page or
shell structure.
Good fits:
- compact navigation vs rail or sidebar navigation
- single-column page vs master-detail page
- list layout vs dashboard layout
- route shell changes
- major content regions that all use the same screen breakpoint
ScreenSize<LayoutSize>(
breakpoints: const Breakpoints(
small: 600,
medium: 950,
large: 1200,
extraLarge: 1400,
),
child: ScreenWidgetBuilder(
extraSmall: (context, data) => const CompactPage(),
medium: (context, data) => const TwoColumnPage(),
large: (context, data) => const WideDashboard(),
),
)
Descendants can read the screen data when they genuinely need it:
final data = ScreenSizeModel.of<LayoutSize>(context);
final breakpoint = ScreenSizeModel.breakpointOf<LayoutSize>(context);
Prefer breakpointOf when the widget only needs the resolved breakpoint.
Screen-Owned Values
Use ScreenValueBuilder when the full screen owns the decision but only one
value changes.
Good fits:
- page padding
- grid columns
- content max width
- toolbar density
- icon size
ScreenValueBuilder<int, Object?>(
extraSmall: 1,
medium: 2,
large: 4,
builder: (context, columns, {data, responsiveValue}) {
return GridView.count(crossAxisCount: columns);
},
)
The branch resolves a value. The callback still returns the widget to render.
Local Parent Constraints
Use LayoutWidgetBuilder or LayoutValueBuilder when a reusable component
should respond to its actual parent width.
Good fits:
- cards used inside narrow and wide regions
- split-pane content
- side panels
- dialogs and sheets
- reusable package widgets
- nested regions whose width differs from the full screen
LayoutWidgetBuilder(
extraSmall: (context) => const CompactCard(),
medium: (context) => const MediumCard(),
large: (context) => const WideCard(),
)
For value-only local decisions:
LayoutValueBuilder<double>(
extraSmall: 8,
medium: 16,
large: 24,
builder: (context, spacing) {
return Padding(
padding: EdgeInsets.all(spacing),
child: const CardContent(),
);
},
)
This matters in split views and panes. A wide desktop window can contain a narrow panel, and the panel should usually respond to its own constraints.
Local Layout Helpers
Use ResponsiveGrid when repeated children should flow into equal-width columns
based on available width and a minimum child width.
ResponsiveGrid(
minChildWidth: 220,
spacing: 12,
runSpacing: 12,
children: cards,
)
Use ResponsiveSectionRow when sections should remain side by side only when
each section can meet its minimum width.
ResponsiveSectionRow(
minSectionWidth: 280,
spacing: 16,
runSpacing: 16,
sections: const [
SummaryPanel(),
DetailsPanel(),
],
)
ResponsiveGridBase and ResponsiveSectionRowBase read constraints from an
existing LayoutConstraintsWrapper. Use the base variants when a parent already
captures constraints for the surrounding layout.
LayoutConstraintsWrapper(
builder: (context, child) => child,
child: ResponsiveSectionRowBase(
minSectionWidth: 320,
sections: const [
BillingSummarySection(),
PaymentMethodSection(),
],
),
)
Shared Responsive Config
Use ScreenSizeWithValue when multiple descendants need one resolved layout
configuration.
class LayoutConfig {
const LayoutConfig({
required this.columns,
required this.padding,
this.showSideMenu = false,
});
final int columns;
final double padding;
final bool showSideMenu;
}
ScreenSizeWithValue<LayoutSize, LayoutConfig>(
breakpoints: Breakpoints.defaultBreakpoints,
valueProvider: ResponsiveValue<LayoutConfig>(
extraSmall: const LayoutConfig(columns: 1, padding: 12),
medium: const LayoutConfig(columns: 2, padding: 16),
large: const LayoutConfig(
columns: 3,
padding: 24,
showSideMenu: true,
),
),
child: const FeatureShell(),
)
Read the value from descendants:
final config =
ScreenSizeModelWithValue.responsiveValueOf<LayoutSize, LayoutConfig>(
context,
);
Use ScreenWithValueWidgetBuilder when each branch needs the shared config:
ScreenWithValueWidgetBuilder<LayoutConfig>(
extraSmall: (context, data) {
return CompactLayout(config: data.responsiveValue);
},
large: (context, data) {
return WideLayout(config: data.responsiveValue);
},
)
Good shared values are layout data: padding, section gap, max content width, compact action mode, pane width policy, layout mode, and pane count.
Keep route identity, selected item, edited form data, and business state in the route, page state, or app state layer that owns them.
Material 3 Window Classes
Use MaterialResponsiveSize when Material 3 window size classes and adaptive
layout values should drive the subtree.
MaterialApp(
builder: (context, child) {
return MaterialResponsiveSize(
child: child ?? const SizedBox.shrink(),
);
},
home: const HomePage(),
)
MaterialResponsiveSize wraps the subtree in:
ScreenSizeWithValue<MaterialWindowSizeClass, MaterialResponsiveValues>
Read the current Material class:
final windowClass =
ScreenSizeModelWithValue.breakpointOf<MaterialWindowSizeClass>(context);
Read the resolved Material values:
final values = ScreenSizeModelWithValue.responsiveValueOf<
MaterialWindowSizeClass, MaterialResponsiveValues>(context);
return ListView(
padding: EdgeInsets.all(values.pageMargin),
children: [
ResponsiveSectionRow(
minSectionWidth: values.fixedPaneWidth ?? 280,
spacing: values.paneSpacing,
sections: sections,
),
],
);
MaterialResponsiveValues includes values such as pageMargin, paneSpacing,
recommendedPaneCount, maxPaneCount, fixedPaneWidth, and
sideSheetMaxWidth. It also exposes constants for Material sizing rules such as
touch targets, pointer targets, dialogs, bottom sheets, search, snackbars,
progress indicators, toolbars, and carousel constraints.
Use custom MaterialBreakpoints only when the product intentionally shifts the
Material thresholds:
MaterialResponsiveSize(
breakpoints: const MaterialBreakpoints(
medium: 640,
expanded: 900,
large: 1240,
extraLarge: 1600,
),
child: const AppShell(),
)
Orientation And Shortest Side
Use orientation variants when portrait and landscape need different payloads within the same breakpoint family.
ScreenWidgetBuilderOrientation(
small: (context, data) => const PortraitCompactPage(),
smallLandscape: (context, data) => const LandscapeCompactPage(),
large: (context, data) => const WidePage(),
)
The same pattern exists for screen values, local layout widgets, local layout values, shared-value builders, and granular APIs.
Use useShortestSide when the responsive class should be based on the shorter
dimension instead of width.
Good fits:
- square-ish constrained components
- orientation-sensitive surfaces where height limits matter
- layouts that should stay compact if either dimension is narrow
Architecture And State
Screen-wide builders are strongest at app, route, feature, and page boundaries. Local builders are strongest inside reusable widgets and constrained layout regions.
For shell-level layout, keep durable state owners above responsive branches that can unmount:
- nested routers
- tab controllers
- scroll controllers and page storage
- form controllers and form keys
- provider scopes or cache wrappers that preserve page state
- state wrappers that can briefly show loading or error UI
Branches should replace responsive chrome around stable state. For example, a compact shell and desktop shell can wrap the same child router with different navigation UI.
For route-derived UI state, prefer deriving selected shell state from the current route. A short-lived local cache can bridge transition frames when navigation has just changed and the route tree has not finished rebuilding.
For component-level layout, pass a resolved value through constructor parameters when only one subtree needs it. Use inherited responsive values when many unrelated descendants need the same layout constants. Use local constraints when the child should respond to the actual space its parent gives it.
Testing Responsive UI
Tests should install the same responsive owner used by the app or feature:
- no global owner for local-only components
ScreenSizefor screen-owned branchesScreenSizeWithValuefor shared responsive configMaterialResponsiveSizefor Material window classes- feature-scoped wrappers when a feature owns custom breakpoints
Test named breakpoints that matter to the product:
extraSmall,small,medium,large,extraLarge- granular tiers such as
compactSmall,standardNormal, andstandardExtraLarge - any custom threshold that changes behavior
When testing shell routes, include at least one resize or branch change for state that should survive:
- selected tab
- active detail row
- scroll offset
- expanded section
- partially edited form field
- dismissed local page flag
When responsive values matter, test exact values and fallback behavior.
LLM Usage Skill
The package includes a skill for LLM coding agents:
skills/topical-responsive-size-builder/SKILL.md
The skill teaches agents to:
- classify whether a task is about API mechanics, implementation architecture, or both
- choose the responsive owner before choosing an API
- use screen APIs for app-window decisions
- use layout APIs for parent-constraint decisions
- use value builders for scalar decisions
- use shared responsive config when a subtree needs one layout contract
- preserve routers, controllers, provider scopes, and page state across responsive branches
- review common responsive mistakes
The skill also links to focused references:
- Screen API
- Screen With Value API
- Layout API
- Local Layout Helpers API
- Material API
- Breakpoints And Resolution
- Shell, Navigation, And State
- Component And Local Layout
- Testing Responsive Implementation
- Patterns To Avoid
For LLM workflows, this README is the broad human guide and the skill is the agent-facing operational guide.
Example App
The example/ app demonstrates the main API families:
- screen builders
- screen value builders
- local layout builders
- local layout value builders
- shared responsive values
- granular breakpoints
- orientation variants
- Material 3 responsive values
Run it with:
cd example
flutter run
License
MIT
Libraries
- responsive_size_builder
- Public entrypoint for the responsive_size_builder package.