flutter_page_scaffold 0.4.1
flutter_page_scaffold: ^0.4.1 copied to clipboard
A reusable main content area template widget with page titles, section headers, and theme-aware styling.
flutter_page_scaffold #
A reusable Flutter widget package for consistent, theme-aware main content area layouts. Provides structured page templates with bold titles, section headers with accent bars, and grouped content cards.

Features #
- MainAreaTemplate -- Page-level wrapper with large title, description, icon, and action buttons
- MainAreaSection -- Grouped content card with accent-bar section headers
- Unified title-tab bar -- Pill-style tabs merged into the title row for compact navigation
- Card-free mode --
showCard: falsefor dashboard-style floating layouts - Fully theme-aware -- All colors derived from
Theme.of(context), works with anyThemeData - Zero dependencies -- Only requires Flutter SDK
Installation #
Add to your pubspec.yaml:
dependencies:
flutter_page_scaffold: ^0.4.0
Then run:
flutter pub get
Usage #
Basic page layout #
import 'package:flutter_page_scaffold/flutter_page_scaffold.dart';
MainAreaTemplate(
title: 'Network Devices',
description: 'Manage network switches across all domains.',
icon: Icons.router,
actions: [
FilledButton.icon(
onPressed: () {},
icon: const Icon(Icons.add),
label: const Text('Add'),
),
],
child: Column(
children: [
MainAreaSection(
label: 'TOOLBAR',
child: Row(children: [/* toolbar content */]),
),
const SizedBox(height: 12),
MainAreaSection(
label: 'DATA',
expanded: true,
child: MyDataTable(),
),
],
),
)
Tabbed page layout (unified bar) #
When tabs is provided, the title and tabs merge into a single unified bar with pill-style tab chips. The description text becomes a tooltip (hover the ? icon).
MainAreaTemplate(
title: 'Network Manager',
description: 'Manage network infrastructure.', // shown as tooltip
icon: Icons.router,
actions: [
FilledButton.icon(
onPressed: () {},
icon: const Icon(Icons.add),
label: const Text('Add Device'),
),
],
tabs: [
PageTab(
label: 'Devices',
icon: Icons.table_chart_outlined,
child: Column(children: [/* device list content */]),
),
PageTab(
label: 'Settings',
icon: Icons.settings_outlined,
child: Column(children: [/* settings content */]),
),
],
onTabChanged: (index) => print('Switched to tab $index'),
)
Tab animation and state control #
MainAreaTemplate(
title: 'Manager',
maintainState: false, // dispose unselected tabs
tabTransitionDuration: const Duration(milliseconds: 200), // fade animation
tabs: [
PageTab(label: 'Tab A', child: ContentA()),
PageTab(label: 'Tab B', child: ContentB()),
],
)
Custom tab bar #
MainAreaTemplate(
title: 'Custom',
tabs: [
PageTab(label: 'One', child: ContentOne()),
PageTab(label: 'Two', child: ContentTwo()),
],
tabBarBuilder: (tabs, selectedIndex, onTabSelected) {
return Row(
mainAxisSize: MainAxisSize.min,
children: [
for (int i = 0; i < tabs.length; i++)
TextButton(
onPressed: () => onTabSelected(i),
child: Text(tabs[i].label),
),
],
);
},
)
Dashboard layout (no card) #
MainAreaTemplate(
title: 'Dashboard',
icon: Icons.home_rounded,
showCard: false, // content floats directly on page background
child: Column(
children: [
Expanded(child: Row(children: [Card(...), Card(...), Card(...)])),
Expanded(child: Row(children: [Card(...), Card(...)])),
],
),
)
When showCard is false, MainAreaSection widgets automatically switch from grey to white backgrounds with individual shadows via PageScaffoldScope.
Visibility control #
The unified bar responds to showTitle and showTabs independently:
// Tabs only (no title/icon)
MainAreaTemplate(
title: 'Manager', // still required but hidden
showTitle: false,
tabs: [
PageTab(label: 'Tab A', child: ContentA()),
PageTab(label: 'Tab B', child: ContentB()),
],
)
// Title only (tabs hidden, content still switches via initialTabIndex)
MainAreaTemplate(
title: 'Manager',
showTabs: false,
tabs: [...],
)
// Both hidden (just the card content)
MainAreaTemplate(
title: 'Manager',
showTitle: false,
showTabs: false,
tabs: [...],
)
API Reference #
MainAreaTemplate #
| Property | Type | Default | Description |
|---|---|---|---|
title |
String |
required | Large bold page title |
description |
String? |
null |
Tooltip in tabbed mode; visible subtitle in no-tabs mode |
icon |
IconData? |
null |
Icon displayed before the title in a tinted container |
actions |
List<Widget>? |
null |
Action buttons at the trailing edge of the title bar |
child |
Widget? |
null |
Main content (required when tabs is null) |
outerPadding |
EdgeInsetsGeometry? |
EdgeInsets.all(24) |
Padding around the template |
cardPadding |
EdgeInsetsGeometry? |
EdgeInsets.all(20) |
Padding inside the content card |
tabs |
List<PageTab>? |
null |
Tab definitions; enables unified title-tab bar |
showTitle |
bool |
true |
Show/hide title, icon, and description in the bar |
showTabs |
bool |
true |
Show/hide tab pills (only when tabs is provided) |
showCard |
bool |
true |
Wrap content in a card container with rounded corners and shadow |
initialTabIndex |
int |
0 |
Starting tab index |
onTabChanged |
ValueChanged<int>? |
null |
Callback when selected tab changes |
maintainState |
bool |
true |
Keep all tab children mounted via IndexedStack |
tabTransitionDuration |
Duration? |
null |
Fade animation duration when switching tabs |
tabBarBuilder |
TabBarBuilder? |
null |
Custom tab bar widget builder (replaces pill tabs) |
PageTab #
| Property | Type | Default | Description |
|---|---|---|---|
label |
String |
required | Tab label displayed in the pill chip |
icon |
IconData? |
null |
Icon displayed before the label inside the pill |
child |
Widget |
required | Content widget shown when this tab is selected |
MainAreaSection #
| Property | Type | Default | Description |
|---|---|---|---|
label |
String? |
null |
Uppercase section header with accent bar |
child |
Widget |
required | Section content |
padding |
EdgeInsetsGeometry? |
EdgeInsets.all(16) |
Padding around content |
expanded |
bool |
false |
If true, fills remaining space in a Column |
PageScaffoldScope #
An InheritedWidget provided by MainAreaTemplate that exposes configuration to descendant widgets. MainAreaSection reads this automatically to adjust its appearance when showCard changes.
final scope = PageScaffoldScope.maybeOf(context);
if (scope != null && !scope.showCard) {
// card-free mode — sections use surface color with shadow
}
Theme Integration #
All colors are pulled from Theme.of(context).colorScheme:
| Widget element | Color token |
|---|---|
| Page background | scaffoldBackgroundColor |
| Content card | surface |
| Section background | surfaceContainerHighest (or surface when showCard: false) |
| Accent bar | primary |
| Title text | onSurface |
| Description text | onSurfaceVariant |
| Section header text | onSurfaceVariant |
| Card shadow | shadow (6% opacity) |
| Selected tab pill | primary (8% alpha bg, solid text) |
| Unselected tab text | onSurfaceVariant |
| Bar separator | outlineVariant |
Works out of the box with light, dark, or any custom ThemeData.
Example #
A playground app is included in example/. Run it with:
cd example
flutter run -d chrome
The playground demonstrates three page layouts (table, settings, dashboard) with toggles for title, tabs, keep-alive, animation, card mode, and a theme switcher for light, dark, and sunshine themes.
License #
MIT