widget-previewer
Flutter Widget Previewer
Preview Flutter widgets in real-time, separate from a full app, in the Chrome browser.
Requirements
- Flutter version 3.35 or higher (for basic functionality)
- Flutter version 3.38 or higher (for IDE support)
- Chrome browser
Starting the Widget Previewer
From IDEs (Flutter 3.38+)
IDEs automatically start the Widget Previewer on launch:
Android Studio / IntelliJ: Open the "Flutter Widget Preview" tab in the sidebar
Visual Studio Code: Open the "Flutter Widget Preview" tab in the sidebar
From Command Line
flutter widget-preview start
This launches a local server and opens Chrome with the Widget Preview environment.
Basic Preview Usage
Import the preview package and use the @Preview annotation:
import 'package:flutter/widget_previews.dart';
import 'package:flutter/material.dart';
(name: 'My Sample Text')
Widget mySampleText() {
return const Text('Hello, World!');
}
Valid @Preview Targets
- Top-level functions returning
WidgetorWidgetBuilder - Static methods within a class returning
WidgetorWidgetBuilder - Public Widget constructors and factories with no required arguments
Preview Controls
Each preview instance provides controls (left to right):
- Zoom in: Magnify the widget
- Zoom out: Reduce magnification
- Reset zoom: Return to default zoom level
- Toggle light/dark mode: Switch theme
- Hot restart: Restart only this specific preview
For global state changes, use the hot restart button at the bottom right of the environment.
Customizing Previews
The @Preview annotation accepts these parameters:
| Parameter | Type | Description |
|---|---|---|
name |
String | Descriptive name for the preview |
group |
String | Group name to organize related previews |
size |
Size | Artificial size constraints |
textScaleFactor |
double | Custom font scale |
wrapper |
Function | Widget tree wrapper (e.g., for InheritedWidget state) |
theme |
Function | Material/Cupertino theming data provider |
brightness |
Brightness | Initial theme brightness |
localizations |
Function | Localization configuration |
Example with multiple parameters:
(
name: 'Button - Large',
group: 'Buttons',
size: Size(200, 100),
textScaleFactor: 1.5,
brightness: Brightness.dark,
)
Widget largeButton() => ElevatedButton(
onPressed: () {},
child: const Text('Large Button'),
);
Creating Custom Preview Annotations
Extend Preview to reduce boilerplate for common configurations:
final class MyCustomPreview extends Preview {
const MyCustomPreview({
super.name,
super.group,
super.size,
super.textScaleFactor,
super.wrapper,
super.brightness,
super.localizations,
}) : super(theme: MyCustomPreview.themeBuilder);
static PreviewThemeData themeBuilder() {
return PreviewThemeData(
materialLight: ThemeData.light(),
materialDark: ThemeData.dark(),
);
}
}
Runtime Transformations
Override transform() for runtime preview modifications:
final class TransformativePreview extends Preview {
const TransformativePreview({
super.name,
super.group,
super.size,
super.textScaleFactor,
super.wrapper,
super.brightness,
super.localizations,
});
PreviewThemeData _themeBuilder() {
return PreviewThemeData(
materialLight: ThemeData.light(),
materialDark: ThemeData.dark(),
);
}
Preview transform() {
final originalPreview = super.transform();
final builder = originalPreview.toBuilder();
builder
..name = 'Transformed - ${originalPreview.name}'
..theme = _themeBuilder;
return builder.toPreview();
}
}
Multiple Preview Configurations
Apply multiple @Preview annotations for different configurations:
(
group: 'Brightness',
name: 'Example - light',
brightness: Brightness.light,
)
(
group: 'Brightness',
name: 'Example - dark',
brightness: Brightness.dark,
)
Widget buttonPreview() => const ButtonShowcase();
MultiPreview for Batched Configurations
Extend MultiPreview to create custom multi-preview annotations:
final class MultiBrightnessPreview extends MultiPreview {
const MultiBrightnessPreview();
List<Preview> get previews => const [
Preview(
group: 'Brightness',
name: 'Example - light',
brightness: Brightness.light,
),
Preview(
group: 'Brightness',
name: 'Example - dark',
brightness: Brightness.dark,
),
];
}
()
Widget buttonPreview() => const ButtonShowcase();
MultiPreview with Runtime Transformations
final class MultiBrightnessPreview extends MultiPreview {
const MultiBrightnessPreview({required this.name});
final String name;
List<Preview> get previews => const [
Preview(brightness: Brightness.light),
Preview(brightness: Brightness.dark),
];
List<Preview> transform() {
final previews = super.transform();
return previews.map((preview) {
final builder = preview.toBuilder()
..group = 'Brightness'
..name = '$name - ${preview.brightness!.name}';
return builder.toPreview();
}).toList();
}
}
(name: 'Example')
Widget buttonPreview() => const ButtonShowcase();
IDE Integration
Filtering by Selected File
The widget previewer filters previews based on the currently selected file in your IDE. Toggle "Filter previews by selected file" at the bottom left to disable this behavior.
Restrictions and Limitations
Callback Requirements
All callback arguments must be public and constant for code generation to work.
Unsupported APIs
- Native plugins - Not supported (previewer uses Flutter Web)
dart:io- APIs will throw exceptions when invokeddart:ffi- Widgets will fail to load completely
Widgets with transitive dart:io dependencies load but throw on API calls. Widgets with transitive dart:ffi dependencies fail to load entirely.
Solution: Use conditional imports for platform-specific code:
import 'my_api_stub.dart'
if (dart.library.io) 'my_api_io.dart'
if (dart.library.html) 'my_api_web.dart';
Asset Paths
Use package-based paths for fromAsset APIs:
// Correct
'packages/my_package_name/assets/my_image.png'
// Incorrect
'assets/my_image.png'
Unconstrained Widgets
Automatically constrained to ~50% of previewer dimensions. Apply explicit size parameters for consistent behavior.
Multi-Project Support
Currently supports only single projects or Pub workspaces. Multi-project IDE sessions are not yet supported.
Troubleshooting
| Issue | Solution |
|---|---|
| Widget not appearing | Verify @Preview annotation is on valid target (top-level function, static method, or public constructor with no required args) |
| dart:io errors | Use conditional imports to provide web-compatible implementations |
| dart:ffi errors | Isolate ffi-dependent code and exclude from preview targets |
| Assets not loading | Use package-based asset paths |
| IDE not showing previewer | Ensure Flutter 3.38+ and check IDE plugin settings |
| Previews not updating | Try hot restart on individual preview or global hot restart |
References
- API Documentation
- Flutter Widget Previewer Guide - Complete documentation reference