Explain the Scaffold widget
2 min read
Widgets & UI
Theory — Scaffold's slots
| Slot | Purpose |
|---|---|
appBar | Top toolbar (AppBar, SliverAppBar via CustomScrollView) |
body | Main content (where you put your ListView, Column, etc.) |
floatingActionButton + floatingActionButtonLocation | Primary action button |
drawer / endDrawer | Side navigation panels |
bottomNavigationBar | Persistent bottom navigation |
bottomSheet | Persistent bottom sheet (always visible) |
backgroundColor, resizeToAvoidBottomInset, extendBody | Behaviour & styling toggles |
Above the Scaffold sits ScaffoldMessenger (auto-included by MaterialApp) — that's what owns snackbars so they survive route changes.
Code in action
Scaffold(
appBar: AppBar(
title: const Text('Inbox'),
actions: [IconButton(icon: const Icon(Icons.search), onPressed: () {})],
),
body: ListView(children: messages.map(MessageTile.new).toList()),
floatingActionButton: FloatingActionButton(
onPressed: _compose,
child: const Icon(Icons.edit),
),
drawer: const NavigationDrawer(),
bottomNavigationBar: NavigationBar(
destinations: const [
NavigationDestination(icon: Icon(Icons.inbox), label: 'Inbox'),
NavigationDestination(icon: Icon(Icons.send), label: 'Sent'),
],
selectedIndex: _index,
onDestinationSelected: (i) => setState(() => _index = i),
),
)
Calling Scaffold features from elsewhere
// SnackBar — use ScaffoldMessenger (survives navigation)
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(content: Text('Saved')),
);
// Open the side drawer
Scaffold.of(context).openDrawer();
// Persistent bottom sheet (lives inside Scaffold)
Scaffold.of(context).showBottomSheet((_) => SizedBox(height: 200));
// Modal bottom sheet (covers Scaffold, dismissible)
showModalBottomSheet(context: context, builder: (_) => SizedBox(height: 200));
Reminder from Q18: Scaffold.of(context) needs a context below the Scaffold — wrap with Builder when calling from the same build method.
When to use what
| Situation | Reach for |
|---|---|
| Standard app screen with a top bar | Scaffold + AppBar |
| Collapsing/parallax header | CustomScrollView + SliverAppBar inside Scaffold |
| Persistent bottom area (mini-player, cart summary) | bottomSheet |
| Temporary modal (filters, picker) | showModalBottomSheet |
| Side menu | drawer or endDrawer |
| Toast / undo bar | ScaffoldMessenger.showSnackBar |
| iOS-style page | Consider CupertinoPageScaffold instead |
Common mistakes to avoid
// ❌ Calling Scaffold.of(context) from the same build that creates the Scaffold
return Scaffold(
body: ElevatedButton(
onPressed: () => Scaffold.of(context).openDrawer(), // ⚠️ throws
...
),
);
// ✅ Wrap in a Builder to get a context below the Scaffold
// ❌ Stacking SnackBars before ScaffoldMessenger existed
// Use ScaffoldMessenger.of(context).showSnackBar(...) — survives navigation
// ❌ Using Scaffold inside a Scaffold for no reason
// Multiple Scaffolds = nested message queues, drawers etc. Use one per route.
// ❌ Hiding behind a notch / keyboard
// Use SafeArea around custom-positioned content; leave resizeToAvoidBottomInset true
// unless you specifically need otherwise.
// ❌ Forgetting that the FAB is auto-positioned by floatingActionButtonLocation
// Don't try to Stack/Positioned a FAB inside body — let the Scaffold do its job.
Interview follow-ups
-
Why use
ScaffoldMessengerinstead ofScaffold.offor SnackBars?ScaffoldMessengeris above the Navigator, so SnackBars persist across route changes and don't depend on the right Scaffold being in scope.Scaffold.of(context).showSnackBarwas deprecated for that reason. -
What does
resizeToAvoidBottomInsetactually do? When true (default), the Scaffold's body shrinks to leave room for the on-screen keyboard. Setting it to false lets the keyboard overlap content — useful for chat screens where you manage the layout yourself. -
Persistent
bottomSheetvsshowModalBottomSheet?bottomSheetis part of the Scaffold and is always visible while the page is on top.showModalBottomSheetis a route-like overlay that dims the background, is dismissible, and pops withNavigator.pop. Different use cases. -
When would you use
CustomScrollView+SliverAppBarinstead ofappBar? When you need a collapsible/stretchy header, a sticky search bar, or to interleave multiple scrollable regions. A regularAppBaris fixed; aSliverAppBarparticipates in the scroll.
How helpful was this content?
Please sign in to rate this article.