Layout Constraining
When running golden tests, Widgetbook uses the smallest possible size that fits the widget.
For components that expand to fill available space, constrain the layout with ViewportMode.
Choosing a Viewport Strategy
- Use device-like width with flexible height for scrollable pages and full-screen content.
- Use fully constrained width and height when you need strict layout bounds (for example, floating action buttons or bottom overlays).
final $Default = _Story(
modes: [
// Applied to all scenarios in this story,
ViewportMode(
const ViewportData.constrained(
name: '800w',
maxWidth: 800,
pixelRatio: 2,
platform: TargetPlatform.iOS,
),
),
],
scenarios: [
_Scenario(
// Uses the constrained viewport defined above.
name: '800w',
),
_Scenario(
name: '600w',
modes: [
// Merged with story-level modes.
// Scenario modes have higher precedence.
ViewportMode(
const ViewportData.constrained(
name: '600w',
maxWidth: 600,
pixelRatio: 2,
platform: TargetPlatform.iOS,
),
),
],
),
],
);
Constrain Size Per Story
Apply a constrained viewport at the story level to affect all scenarios in that story.
final $ProfileScreen = _Story(
modes: [
ViewportMode(
const ViewportData.constrained(
name: 'iPhone-Width',
maxWidth: 390,
pixelRatio: 3,
platform: TargetPlatform.iOS,
),
),
],
);
Override Size Per Scenario
If needed, define another viewport mode directly on a scenario. Scenario-level modes are merged with story-level modes and take precedence.
final $ProfileScreen = _Story(
modes: [
ViewportMode(
const ViewportData.constrained(
name: 'Tablet',
maxWidth: 1024,
pixelRatio: 2,
platform: TargetPlatform.iOS,
),
),
],
scenarios: [
_Scenario(name: 'Default'),
_Scenario(
name: 'Compact',
modes: [
ViewportMode(
const ViewportData.constrained(
name: 'Phone',
maxWidth: 390,
pixelRatio: 3,
platform: TargetPlatform.iOS,
),
),
],
),
],
);

