Widget Previewer IDE Integration: VS Code, Android Studio, and the CLI
The Flutter Widget Previewer is stable in 3.47 — how to open it from VS Code, Android Studio, IntelliJ, or the command line.
Published on • October 19, 2026
AI Assistant

The Flutter Widget Previewer — the tool that renders individual widgets in real time, separate from a running app — is stable as of Flutter 3.47, per the official docs. If you ignored it while it churned through experimental releases, now is the time to wire it into your workflow. Here’s exactly how it plugs into each IDE, what the command line gives you, and the constraints that still apply.
Opening it from your IDE
The headline behavior is delightfully boring: Android Studio, IntelliJ, and Visual Studio Code automatically start the Widget Previewer on launch. There’s no daemon to configure and no flag to pass. In all three, you open the “Flutter Widget Preview” tab in the IDE sidebar — that’s the entire launch procedure:
- Android Studio / IntelliJ — open the Flutter Widget Preview tab in the sidebar.
- Visual Studio Code — same, the Flutter Widget Preview tab in the sidebar.
Because it starts with the IDE’s Flutter session, edits hit it the same way they hit hot reload: change a widget’s code and the preview updates. When global state mutates (say, a static initializer), you use the whole-previewer hot restart button at the bottom right of the environment; the per-preview hot restart button restarts only that one widget without touching anything else.
An IDE-only feature worth enabling: Filter previews by selected file. Toggle it at the bottom of the environment and the previewer shows only previews from the Dart file you currently have open — invaluable in a monorepo where dozens of @Preview functions exist. (Multi-project caveat below.)
Opening it from the command line
No IDE? Same tool, browser-hosted:
flutter widget-preview start
Run it from your Flutter project root. The command launches a local server and opens a real-time preview environment in your browser. It also caches project builds in a .widget_preview/ folder in your project root to optimize subsequent startups — add that to .gitignore.
Annotating a widget
Neither the IDE tab nor the CLI does anything until you annotate. The @Preview annotation lives in package:flutter/widget_previews.dart and can be applied to:
- Top-level functions returning a
WidgetorWidgetBuilder. - Static methods within a class with the same return types.
- Public widget constructors and factories with no required arguments.
import 'package:flutter/widget_previews.dart';
import 'package:flutter/material.dart';
@Preview(name: 'My Sample Text')
Widget mySampleText() {
return const Text('Hello, World!');
}
Each preview instance gets its own control strip: zoom in, zoom out, reset zoom, the light/dark mode toggle, and a hot restart for that individual preview.
Navigating a large preview set
Projects accumulate previews fast. The environment has a real-time search bar with a filter dropdown supporting four criteria:
- Preview name — the
name:parameter of@Preview. - Group name — the
group:parameter. - Containing script — the URI of the Dart file.
- Containing package — the package name.
@Preview(name: 'Submit Button', group: 'Form Controls')
Widget submitButtonPreview() => const SubmitButton();
Customizing a preview
The annotation’s parameters let you simulate the conditions your widget actually ships into:
size— artificial size constraints via aSizeobject.textScaleFactor— a custom font scale (test accessibility settings without the OS dialog).wrapper— a function that wraps your widget in a specific tree, e.g. to inject anInheritedWidgetcarrying app state.theme— a function returningPreviewThemeData, with sequential theme layering for matrix testing.brightness— the initial theme brightness.localizations— a localization configuration.
Boilerplate elimination comes from extending the annotation itself. A custom final class const MyCustomPreview(...) extends Preview can default theme to your design system’s PreviewThemeData, so every preview in the package renders with your real ThemeData instead of stock Material. Overriding Preview.transform() goes further — it runs at preview time (not const time), letting you rewrite names, themes, and configurations dynamically. For multiples, extend MultiPreview and return a List<Preview>; one annotation then generates a whole light/dark matrix.
Restrictions you’ll hit
The docs are candid about limitations, and you should know them before you blame your code:
- Public, constant callback arguments. Everything you pass to a preview annotation must be public and constant — the previewer’s code generation depends on it.
- No
dart:io,dart:ffi, or native plugins. The previewer is built with Flutter Web. Widgets with transitive dependencies on those libraries now load (a 3.41 improvement), but any actual call into them throws. Structure platform-specific code behind conditional imports. - Asset paths must be package-based. With
fromAssetAPIs, use'packages/my_package_name/assets/my_image.png'rather than'assets/my_image.png'. When previewing web widgets, the previewer syncs assets from your host project’sweb/directory, including custom theming andindex.htmlcustomizations. - Unconstrained widgets get clamped to roughly half the previewer’s width and height. Prefer the
sizeparameter — that auto-clamp behavior is documented as likely to change. - Single project only. IDE sessions displaying previews from multiple Flutter projects aren’t supported yet; the docs track this as issue #173550, including pub workspaces.
The payoff
The point isn’t the pretty sidebar — it’s iteration speed. A preview cycle skips app startup, navigation, and login state, which turns “tweak, rebuild, navigate back, squint” into “tweak, look.” Annotate your design-system components once (group: 'Form Controls', group: 'Cards', and so on), and the previewer becomes a living component catalog that starts with your IDE and filters to whatever file you’re editing.