What's new in Widgetbook 4?

Widgetbook 4 introduces a generated, Storybook-aligned API with stronger typing, clearer structure, better support for docs and testing, and reduced pricing for Widgetbook Cloud. If you're migrating from Widgetbook 3, this page highlights what changed and why it matters.

This version is currently in beta and may be unstable. API-defining changes can still occur in minor releases. Use it at your own risk.

New Syntax

Widgetbook 4 replaces the function-heavy setup from v3 with generated declarations. The result is a more consistent API with better autocompletion and compile-time safety.

Widgetbook 3Widgetbook 4What changed
Use-cases (@UseCase)Stories (_Story)Use-cases are now stories.
Knobs (context.knobs)Args (_Args, StringArg, BoolArg, ...)Knobs are now type-safe args.
Addons onlyAddons + ModesModes define concrete addon setups, for example a theme addon with light and dark modes.
Annotation + function-heavy setupGenerated declarations (Meta, _Story, _Args, _Scenario)Better type-safety, autocompletion, and structure.

The sections below explain each area in more detail.

Simple Example

The snippet below shows the minimal structure of a Widgetbook 4 story definition.

import 'package:widgetbook/widgetbook.dart';

part 'my_widget.stories.g.dart';

const meta = Meta<MyWidget>();

final $Default = _Story(
  name: 'Default',
);

The Meta Argument

Meta<T> declares which component your stories belong to. It acts as the anchor that connects stories, args, and documentation to one widget type.

const meta = Meta<MyWidget>();

When you run build_runner, Widgetbook generates declarations such as _Story, _Args, and _Scenario. These generated APIs reduce boilerplate and make the framework easier to navigate.

Using Meta lets Widgetbook:

  • Group stories under the same component.
  • Generate typed args based on the component contract.
  • Resolve component-level documentation (for example through docsBuilder and doc comments).

Modes for Addons

Modes are reusable addon configurations for rendering a story. Addons define what can be configured (for example theme, locale, or viewport), while modes define the concrete configuration to apply.

final $Button = _Story(
  name: 'Button',
  modes: [
    MaterialThemeMode('Light', ThemeData.light()),
  ],
);

Type-safety with Args

Args are generated from the widget's constructor or a custom interface, making story inputs fully type-safe. This gives you compile-time checks and autocompletion when working with widget properties. Args also make stories reusable in tests, which was harder to do in Widgetbook 3.

class MyText extends StatelessWidget {
  final String text;

  const MyText({
    super.key,
    required this.text,
  });

  @override
  Widget build(BuildContext context) {
    return Text(text);
  }
}

// Widgetbook 3 with Knobs
@UseCase(name: 'Default')
Widget defaultMyText(BuildContext context) {
  return MyText(
    text: context.knobs.text(label: 'Text', initialValue: 'Hello World'),
  );
}

// Widgetbook 4 with Args
final $Default = _Story(
  name: 'Default',
  args: _Args(
    text: StringArg('Hello World'),
    // ^ Arg<String> is type-safe
  ),
);

Component Documentation

Widgetbook 4 introduces automatic component documentation powered by DocBlocks. Documentation is generated from your components and stories and can be customized globally in Config or per component via Meta.

// Global configuration
final config = Config(
  components: components,
  docsBuilder: () => [
    const ComponentNameDocBlock(),
    const DartCommentDocBlock(),
    const StoriesDocBlock(),
  ],
);

// Component-level customization
final meta = Meta<MyWidget>(
  docsBuilder: (blocks) => blocks
    ..insertAfter<ComponentNameDocBlock>(
      const TextDocBlock('Additional context for this component.'),
    ),
);

Golden Testing

Widgetbook 4 introduces Scenarios, which are story-level test configurations similar to golden test cases. A scenario lets you define specific args and mode values for a story, so you can test different widget states consistently.

Scenarios are currently generated in build/.widgetbook by running flutter test.

final $Primary = _Story(
  name: 'Primary',
  scenarios: [
    _Scenario(
      name: 'Enabled',
      args: _Args(
        label: StringArg('Click Me'),
        isEnabled: BoolArg(true),
      ),
    ),
    _Scenario(
      name: 'Disabled',
      args: _Args(
        label: StringArg('Click Me'),
        isEnabled: BoolArg(false),
      ),
    ),
  ],
);

Interaction Testing

Widgetbook Cloud supports interaction testing. You can define interactions for stories to simulate user actions and verify widget behavior.

final $Default = _Story(
  name: 'Counter',
  scenarios: [
    _Scenario(
      name: 'Incremented Counter',
      run: (tester, args) async {
        await tester.tap(find.byIcon(Icons.add));
        await tester.pumpAndSettle();

        expect(
          find.text('${args.initialValue + 1}'),
          findsOneWidget,
        );
      },
    ),
  ],
);

Reduced Pricing for Widgetbook Cloud

Previously, every snapshot consumed infrastructure resources even if nothing had changed. With v4, we can detect whether a snapshot is visually identical before running our comparison analysis. Unchanged widgets cost a fraction of what they used to. We're passing those savings directly on to our customers.

Right now, we do not know exactly how much cost savings we will have. We're working closely together with Beta Users to find that out. Sign up for the Widgetbook Cloud v4 Beta Program to get 2,5x more snapshot usage for free immediately as well as individual support calls to shape v4 and the new pricing together with us. We will announce the final pricing plans before general availability.