fabrik_layout
Responsive Flutter code tends to accumulate MediaQuery.of(context).size.width > 600 checks, each with its own slightly different threshold. fabrik_layout
resolves the width once, classifies it, and exposes the result anywhere below:
if (context.layout.isMobile) { … }
final columns = context.layout.value<int>(mobile: 1, tablet: 2, desktop: 3);Classification is by width, not by platform: a narrow window on a desktop
is mobile, which is almost always what layout code means.
Installation
Section titled “Installation”dependencies: fabrik_layout: ^1.2.0import 'package:fabrik_layout/fabrik_layout.dart';Quick start
Section titled “Quick start”Wrap your app once, inside MaterialApp.builder:
MaterialApp( builder: (context, child) => FabrikLayout(child: child!), home: const HomePage(),);Then read layout data anywhere below it:
Widget build(BuildContext context) { final layout = context.layout;
return Padding( padding: EdgeInsets.all(layout.isMobile ? 16 : 32), child: layout.isMobile ? const MobileNav() : const SidebarNav(), );}Guides
Section titled “Guides”Pick values per device
Section titled “Pick values per device”value<T>() is usually clearer than branching on isMobile. Only mobile is
required; wider categories fall back to the next smaller value:
final padding = context.layout.value<double>( mobile: 16, tablet: 24, desktop: 32,);
final columns = context.layout.value<int>( mobile: 1, tablet: 2, desktop: 3, largeDesktop: 4,);
// Falls back to the mobile value on every wider screenfinal showLabels = context.layout.value<bool>(mobile: false, desktop: true);Because the fallback cascades, you can describe only the breakpoints you care about and ignore the rest.
Understand the four bands
Section titled “Understand the four bands”| Category | Default width | isDesktopOrWider |
|---|---|---|
mobile | < 600 | no |
tablet | 600 – 1023 | no |
desktop | 1024 – 1439 | yes |
largeDesktop | >= 1440 | yes |
largeDesktop is a refinement of desktop, not a replacement. Most apps
never mention it — value() reuses the desktop value automatically.
Customise breakpoints
Section titled “Customise breakpoints”Each value is the upper bound of the category below it:
FabrikLayout( breakpoints: const FabrikBreakpoints( mobile: 480, // mobile is < 480 tablet: 768, // tablet is 480 – 767 desktop: 1280, // desktop is 768 – 1279, largeDesktop is >= 1280 ), child: child!,);Values must increase; FabrikBreakpoints asserts mobile < tablet < desktop.
Nesting and unbounded width
Section titled “Nesting and unbounded width”FabrikLayout classifies using the width it is given. Inside a bounded box
that is the box, which is what you want for a split-pane layout:
Row( children: [ const SizedBox(width: 280, child: Sidebar()), Expanded( // Classifies against the remaining width, not the window child: FabrikLayout(child: const ContentPane()), ), ],);Under a horizontally scrolling ancestor the available width is infinite, so
there is nothing meaningful to classify. In that case FabrikLayout falls
back to the window width, so a phone is still classified as mobile rather
than silently becoming the widest category.
Even so, the clearest placement is above any horizontal scrolling — usually
once, in MaterialApp.builder.
Respond to orientation
Section titled “Respond to orientation”final layout = context.layout;
if (layout.isTablet && layout.isLandscape) { return const TwoPaneLayout();}return const SinglePaneLayout();Scale text on larger screens
Section titled “Scale text on larger screens”Text sized for a phone can look small on a desktop monitor. Opt in to a per-device minimum scale:
FabrikLayout( enableTextScaling: true, child: child!,);Defaults are mobile 1.0×, tablet 1.05×, desktop 1.1×; largeDesktop
reuses the desktop floor unless you set it. Override any of them:
FabrikLayout( enableTextScaling: true, textScaleConfig: const FabrikTextScaleConfig( mobile: 1.0, tablet: 1.08, desktop: 1.15, largeDesktop: 1.2, ), child: child!,);API reference
Section titled “API reference”FabrikLayout
Section titled “FabrikLayout”| Parameter | Type | Default | Description |
|---|---|---|---|
child | Widget | required | The subtree that receives layout data |
breakpoints | FabrikBreakpoints | FabrikBreakpoints() | Width thresholds |
enableTextScaling | bool | false | Apply per-device minimum text scale |
textScaleConfig | FabrikTextScaleConfig | FabrikTextScaleConfig() | Scale floors, used when scaling is enabled |
context.layout
Section titled “context.layout”Returns FabrikLayoutData. Throws a StateError if no FabrikLayout
ancestor is present.
| Member | Type | Description |
|---|---|---|
type | FabrikLayoutType | mobile, tablet, desktop, largeDesktop |
isMobile / isTablet | bool | Category checks |
isDesktop | bool | The 1024–1439 band only |
isLargeDesktop | bool | >= 1440 only |
isDesktopOrWider | bool | Desktop or large desktop |
isPortrait / isLandscape | bool | Orientation |
screenSize | Size | Window size from MediaQuery |
textScaler | TextScaler | The resolved scaler |
value<T>(…) | T | Per-category value with fallback |
copyWith(…) | FabrikLayoutData | Copy with replacements |
FabrikBreakpoints
Section titled “FabrikBreakpoints”| Field | Default | Meaning |
|---|---|---|
mobile | 600 | Upper bound of mobile |
tablet | 1024 | Upper bound of tablet |
desktop | 1440 | Upper bound of desktop |
FabrikTextScaleConfig
Section titled “FabrikTextScaleConfig”| Field | Default | Meaning |
|---|---|---|
mobile | 1.0 | Minimum scale on mobile |
tablet | 1.05 | Minimum scale on tablet |
desktop | 1.1 | Minimum scale on desktop |
largeDesktop | null | Falls back to desktop |