# Code Generation

Widgetbook uses Dart's `build_runner` to generate the boilerplate needed for [Stories](/stories/overview), [Args](/args/overview), and [Scenarios](/testing/overview). At the core of this system is `Meta`, a declaration that selects a widget constructor to generate stories for. From a `Meta` declaration and a `part` directive, the generator produces type-safe args, story classes, and a component registry. This lets you focus on writing stories rather than wiring up boilerplate.

## Usage

To set up code generation for a widget, create a `.stories.dart` file with two things: a `part` directive pointing to the generated file, and a `Meta` variable with a constructor tear-off:

```dart title="counter.stories.dart"
import 'package:widgetbook/widgetbook.dart';
import 'package:my_app/counter.dart';

part 'counter.stories.g.dart'; // [!code highlight]

const meta = Meta(Counter.new); // [!code highlight]
```

The `part` directive is required since the generator writes all output into the corresponding `.stories.g.dart` file. `Meta` selects the constructor to inspect; the component widget is derived from the tear-off. Args are derived from that constructor's parameters, and the generator creates a type-safe `_Args` class, a `_Story` class with a default builder, and other generated declarations.

`Meta` takes a single positional argument: a constructor tear-off such as `Counter.new` (the unnamed constructor) or `Counter.compact` (a named constructor). `Meta` variables must be declared as `const`. The name of the `meta` variable itself doesn't matter — the generator finds it by type.

### Component Customization

To customize the component as a whole, declare an optional `ComponentMeta` variable (at most one per stories file). All its parameters are optional:

| Parameter | Type | Description |
| --- | --- | --- |
| `name` | `String` | Override the display name shown in the Widgetbook UI. Defaults to the widget class name. |
| `path` | `String` | Set the navigation path in the Widgetbook UI. By default, the path is derived from the file's directory structure. Wrap folder names in square brackets to create categories (e.g. `[components]/counter`). |
| `docsBuilder` | `DocsBuilderFunction` | Customize the [documentation blocks](/docs/overview) shown for this component. |

```dart title="counter.stories.dart"
// Must be `final` instead of `const` since `docsBuilder` holds a closure.
final component = ComponentMeta(
  name: 'Step Counter',
  path: '[components]/counter',
  docsBuilder: (blocks) => blocks.replaceFirst<DartCommentDocBlock>(
    const TextDocBlock('A counter with increment and decrement controls.'),
  ),
);

const meta = Meta(Counter.new);
```

A `ComponentMeta` without parameters is redundant — omit it unless you need one of the customizations above.

### Defining Stories

Once the generator has run, you can define stories using the generated types. Each story variable must start with `$`. The variable name (without the `$`) becomes the story's display name in the Widgetbook UI:

```dart title="counter.stories.dart"
final $Default = _Story(
  args: _Args(
    initialValue: IntArg(0),
  ),
);

final $StartAtTen = _Story(
  args: _Args(
    initialValue: IntArg(10),
  ),
);
```

## Constructor Variants

Widgets often have multiple constructors that represent distinct variants, like `MyButton()` and `MyButton.icon()`. A stories file can have any number of `Meta` variables — one per constructor, all targeting the same widget:

```dart title="my_button.stories.dart"
const meta = Meta(MyButton.new);

const iconMeta = Meta(MyButton.icon); // [!code highlight]
```

For each `Meta`, the generator emits a full set of types. Types for named constructors are prefixed with the PascalCase constructor name:

```dart title="my_button.stories.dart"
// Stories for MyButton(...)
final $Default = _Story();

// Stories for MyButton.icon(...)
final $Icon = _IconStory(); // [!code highlight]

final $IconLarge = _IconStory(
  args: _IconArgs(size: DoubleArg(48)), // [!code highlight]
);
```

All stories appear in a flat list under the same component, with the story variable's name as the display name. Factory constructors work the same way as named constructors.

## Custom Args

For cases where you need a different args shape, provide `Meta.argsType` with a constructor tear-off of a plain Dart class. The generated args are then derived from that constructor's parameters instead of the widget's:

Since the generator can no longer infer how to construct the widget from these custom args, you must provide a `builder`, either per story or via a shared `defaults` variable.

```dart title="label_badge.stories.dart"
import 'package:widgetbook/widgetbook.dart';
import 'package:my_app/label_badge.dart';

part 'label_badge.stories.g.dart';

const meta = Meta(LabelBadge.new, argsType: NumericBadgeInput.new); // [!code highlight]

class NumericBadgeInput { // [!code highlight]
  NumericBadgeInput({required this.number}); // [!code highlight]
  final int number; // [!code highlight]
} // [!code highlight]
```

Each variant must have a distinct args type.

### Providing a Builder

With a custom args type, each story needs a `builder` that maps the custom args to the actual widget:

```dart title="label_badge.stories.dart"
final $Primary = _Story(
  args: _Args(
    number: IntArg(1),
  ),
  builder: (context, args) {
    return LabelBadge(
      text: args.number.toString(),
    );
  },
);
```

### Defaults

To avoid repeating the same `builder` and `setup` in every story, define a variable of the generated `_Defaults` type. The generated `_Story` class picks it up automatically:

```dart title="label_badge.stories.dart"
final defaults = _Defaults(
  setup: (context, child, args) {
    return Container(
      padding: const EdgeInsets.all(8),
      color: Colors.grey[300],
      child: child,
    );
  },
  builder: (context, args) {
    return LabelBadge(
      text: args.number.toString(),
    );
  },
);
```

The generator matches a defaults variable to its variant by the variable's type, not its name — `_Defaults` applies to the unnamed constructor's stories, `_IconDefaults` to the `.icon` constructor's stories, and so on. Each variant can have at most one defaults variable.

With defaults in place, stories only need to specify their args:

```dart
final $Primary = _Story(
  args: _Args(
    number: IntArg(1),
  ),
);

final $Secondary = _Story(
  args: _Args(
    number: IntArg(2),
  ),
);
```

Individual stories can still override `builder` or `setup` when needed.

### When to Use Custom Args

- The widget constructor has parameters that don't work well as args (callbacks, controllers, complex objects).
- You want to expose a simplified or curated set of interactive controls.
- Multiple widget parameters should be derived from a single arg value.
- The widget depends on a provider and you want args to mirror the provider's properties instead of the widget's constructor. This lets you mock the provider in `setup` using the arg values. See the [Mocking guide](/stories/mocking) for more details.

## Generated Output

Running the generator produces two kinds of output:

- A **per-story part file** (`.stories.g.dart`) for each story file.
- A **global component registry** (`components.g.dart`) at the library root.

### Per-Story File

For each `.stories.dart` file, a `.stories.g.dart` part file is generated containing one set of declarations per `Meta` variable. For named constructors, the PascalCase constructor name is inserted after the underscore (e.g. `_IconStory`) and after the widget name (e.g. `MyButtonIconStory`):

| Declaration | Full Name | Description |
| --- | --- | --- |
| `_Args` | `{Widget}Args` (or `{ArgsClass}Args` for custom args) | Extends `StoryArgs<TWidget>`. Contains one `Arg` field per constructor parameter (or per `argsType` constructor parameter when using custom args), getters for resolved values, and a `.fixed()` constructor. See [Args](/args/overview). |
| `_Story` | `{Widget}Story` | Extends `Story<TWidget, Args>`. When using `Meta`, includes a default `builder` that constructs the widget from args. Accepts `args`, `setup`, `modes`, `scenarios`, and `builder`. See [Stories](/stories/overview). |
| `_Scenario` | `{Widget}Scenario` | Typedef for `Scenario<TWidget, Args>`. Used to define fixed, testable states. See [Scenarios](/testing/overview). |
| `_Defaults` | `{Widget}Defaults` | Typedef for `Defaults<TWidget, Args>`. Used to share a `setup` and `builder` across the variant's stories in the file. |
| `_Component` | `Component<TWidget, StoryArgs<TWidget>>` | Typedef for the component registration type. Generated once per file, as stories from all variants share one component. |

#### Syntactic Sugar

The underscore-prefixed names (`_Story`, `_Args`, etc.) are private typedefs that point to the fully qualified generated classes. They exist so you don't have to repeat the widget name everywhere:

```dart
// Without syntactic sugar, using the full generated names:
final $Primary = CounterStory(
  args: CounterArgs(
    initialValue: IntArg(0),
  ),
);

// With syntactic sugar, using the underscore aliases:
final $Primary = _Story(
  args: _Args(
    initialValue: IntArg(0),
  ),
);
```

Both forms are equivalent. The underscore aliases keep story files concise and consistent regardless of the widget name.

#### The Args Class

The generated `_Args` class wraps each constructor parameter in a typed `Arg<T>`. It provides three ways to interact with each parameter:

- **Arg fields** (e.g. `initialValueArg`): the full `Arg<T>` object, useful when you need to customize the arg's behavior.
- **Value getters** (e.g. `initialValue`): convenience getters that return the resolved value directly.
- **`.fixed()` constructor**: creates args with constant values that won't be interactive in the Widgetbook UI. Useful for [Scenarios](/testing/overview).

```dart
// Interactive args with UI controls:
final $Default = _Story(
  args: _Args(
    initialValue: IntArg(0),
  ),
);

// Fixed args without UI controls (useful for scenarios):
_Scenario(
  name: 'Start at 10',
  args: _Args.fixed(
    initialValue: 10,
  ),
);
```

### Component Registry

A single `components.g.dart` file is generated at the library root. It collects every `{Widget}Component` variable into a list that Widgetbook uses to build the navigation tree:

```dart title="components.g.dart"
final components = <Component>[
  CounterComponent,
  ButtonComponent,
  LabelBadgeComponent,
];
```

This file is regenerated whenever you add or remove story files.

## Running the Generator

Run the generator from your Widgetbook package directory:

```bash
dart run build_runner build
```

### Watch Mode

For a smoother workflow, run the generator in **watch mode**. It re-generates automatically on every file save, so the generated types (`_Story`, `_Args`, etc.) stay up to date and your IDE autocompletion always works:

```bash
dart run build_runner watch
```

<Info>
  Watch mode is strongly recommended during development. It removes the need to manually re-run the build command every time you add a story, change args, or modify your widget's constructor.
</Info>

## Best Practices

1. **Use watch mode during development.** Running `dart run build_runner watch` keeps generated code in sync with your source files automatically.
2. **Set up `Meta` before writing stories.** Create the `meta` variable and `part` directive first, run the generator once, and then start writing stories. This ensures `_Story`, `_Args`, and other generated types are available for autocompletion in your IDE.
3. **Prefer widget-derived args over custom args.** Without `argsType`, you get an auto-generated `builder`, so you don't need to manually map args to widget parameters. Only provide `argsType` when the widget's constructor doesn't fit your needs.
4. **Prefix story variables with `$`.** The generator requires this prefix (e.g. `$Default`, `$Primary`) and strips the `$` to derive the display name shown in the Widgetbook UI.
