How to Set Up Widget Previews with the previews.dart System in Flutter
You set up widget previews by importing package:flutter/widget_previews.dart, annotating top-level functions or static methods that return Widgets with @Preview, and launching the Flutter Widget Previewer via your IDE or the flutter widget-preview start command.
The previews.dart system enables isolated widget rendering with instant hot refresh, allowing you to experiment with themes, sizes, and brightness configurations without launching the full application. According to the flutter/skills repository, the previewer scans your codebase for these annotations and generates interactive preview cards in a web-based interface. This workflow, detailed in the repository’s SKILL.md file, integrates directly with Android Studio, IntelliJ, and VS Code to provide a visual development environment.
Understanding Annotation Targets and Requirements
The previewer discovers annotations by parsing Dart files according to the "Target Elements" rules defined in SKILL.md. You can apply @Preview to three specific code elements:
- Top-level functions that return a
WidgetorWidgetBuilder - Static methods inside a class that return a
Widget - Public constructors or factories that have no required arguments
Any target you annotate must be importable and return a valid Flutter widget tree. The system ignores private functions or constructors with required positional parameters, ensuring the previewer can instantiate widgets automatically.
Creating Basic Previews with @Preview
Start by importing the preview package and adding the annotation to a simple widget-building function. The @Preview class accepts parameters including name, group, size, theme, and brightness to categorize and configure the visual output.
import 'package:flutter/widget_previews.dart';
import 'package:flutter/material.dart';
@Preview(name: 'My Sample Text', group: 'Typography')
Widget mySampleText() {
return const Text('Hello, World!');
}
When the Flutter Widget Previewer runs, it detects this annotation and renders a preview card labeled "My Sample Text" within the "Typography" group. You can place multiple @Preview annotations on the same target if you want to display the widget under different configurations simultaneously.
Advanced Configuration with Custom Preview Classes
For dynamic configurations that cannot be expressed with constant values, extend the Preview class and override the transform() method. This approach allows runtime manipulation of names, themes, and other metadata before the preview renders.
import 'package:flutter/widget_previews.dart';
import 'package:flutter/material.dart';
final class TransformativePreview extends Preview {
const TransformativePreview({super.name, super.group});
PreviewThemeData _themeBuilder() => PreviewThemeData(
materialLight: ThemeData.light(),
materialDark: ThemeData.dark(),
);
@override
Preview transform() {
final original = super.transform();
final builder = original.toBuilder()
..name = 'Transformed - ${original.name}'
..theme = _themeBuilder;
return builder.toPreview();
}
}
@TransformativePreview(name: 'Custom Themed Button')
Widget myButton() => const ElevatedButton(onPressed: null, child: Text('Click'));
The transform() method receives the base configuration and returns a modified Preview instance. Use the toBuilder() pattern to clone existing settings while overriding specific properties programmatically.
Generating Multiple Variations with @MultiPreview
When you need to render the same widget under multiple conditions (such as light and dark themes), use the @MultiPreview annotation. Create a class extending MultiPreview and implement the previews getter to return a list of base configurations. Override transform() to dynamically assign names and groups to each variation.
import 'package:flutter/widget_previews.dart';
import 'package:flutter/material.dart';
final class MultiBrightnessPreview extends MultiPreview {
const MultiBrightnessPreview({required this.name});
final String name;
@override
List<Preview> get previews => const [
Preview(brightness: Brightness.light),
Preview(brightness: Brightness.dark),
];
@override
List<Preview> transform() {
return super.transform().map((p) {
final b = p.toBuilder()
..group = 'Brightness'
..name = '$name - ${p.brightness!.name}';
return b.toPreview();
}).toList();
}
}
@MultiBrightnessPreview(name: 'Primary Card')
Widget cardPreview() => const Card(
child: Padding(padding: EdgeInsets.all(8.0), child: Text('Content')),
);
This generates two separate preview cards—one for light mode and one for dark mode—both grouped under "Brightness" with descriptive names derived from the runtime state.
Launching the Flutter Widget Previewer
You can start the previewer through IDE integration or the command line. For IDE support (available in Flutter 3.38+), open a Flutter project in Android Studio, IntelliJ, or VS Code; the previewer starts automatically and displays a "Flutter Widget Preview" tab.
From the terminal, navigate to your project root and execute:
flutter widget-preview start
This command compiles the preview environment and opens a Chrome window serving the web-based UI. The interface provides two hot-restart options: a Global button that restarts all previews (necessary when static state changes) and Per-card buttons that restart individual previews while preserving state for others.
Handling Native API Limitations
Because the previewer runs in a lightweight web environment, any widget depending on native APIs such as dart:io or dart:ffi will fail to render. The SKILL.md documentation in the flutter/skills repository explicitly warns against these dependencies.
To work around this limitation, use conditional imports to provide mock implementations when running in preview mode. Structure your code to abstract platform-specific logic behind interfaces that can return stub values in the web context.
Summary
- Import
package:flutter/widget_previews.dartto access the@Previewand@MultiPreviewannotations. - Annotate top-level functions, static methods, or zero-argument constructors that return
Widgetinstances. - Configure static metadata like
name,group,size, andbrightnessdirectly in the annotation constructor. - Extend
PrevieworMultiPreviewand overridetransform()to generate dynamic configurations using thetoBuilder()pattern. - Launch the previewer via
flutter widget-preview startor through IDE integration (Flutter 3.38+). - Avoid
dart:ioanddart:ffidependencies, or use conditional imports to mock native APIs for the web-based preview environment.
Frequently Asked Questions
What is the previews.dart system in Flutter?
The previews.dart system is a development tool that renders Flutter widgets in isolation using a lightweight web environment. It allows developers to visualize components instantly with hot refresh by scanning for @Preview annotations in the codebase, as implemented in the flutter/skills repository's widget preview workflow.
Which functions can I annotate with @Preview?
You can annotate top-level functions returning Widget or WidgetBuilder, static methods inside classes, and public constructors or factories that have no required arguments. Private members and functions with required parameters are not eligible for preview generation according to the target element rules.
How do I launch the widget previewer from the command line?
Run flutter widget-preview start from your project root directory. This command starts a local server and opens Chrome with the preview interface. The previewer automatically detects file changes and updates the rendered cards, offering both global and per-card hot-restart controls.
Can I use native platform APIs in widget previews?
No. The previewer runs in a browser environment that does not support dart:io, dart:ffi, or other native platform APIs. You must either remove these dependencies from previewed widgets or use conditional imports to provide mock implementations when compiling for the preview environment, as documented in SKILL.md.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →