# Args

Args is a type-safe way to define and manage the properties of your widgets in Widgetbook. 
By using Args, you can create interactive stories that allow you to tweak widget properties in real-time, making it easier to visualize different states and configurations.

Args are generated based on your widget's constructor parameters, ensuring type safety and consistency. 
You can define Args for various data types, including primitives, enums, and complex objects.

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

part 'my_widget.stories.g.dart';

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

Run the following command to generate the `_Args` class for your widget:

```bash
dart run build_runner build
```

Now you can create a story with interactive args using the generated `_Args` class:

```dart title="my_widget.stories.dart"
final $Active = _Story(
  args: _Args(
    title: StringArg('Hello, Widgetbook!'),
    isEnabled: BoolArg(true),
    count: IntArg(5),
    status: Arg.fixed(MyStatus.active), // Constant value, won't be changeable in the UI
  ),
);
```

## Stateful Widgets and Arg Updates

When an arg changes, Widgetbook rebuilds the story with a new key by default.
This behavior is especially useful for `StatefulWidget`s because local state is reset to match the latest arg values.

- `StatelessWidget`: updates reflect immediately through the new args.
- `StatefulWidget`: local state is reset on arg change so the widget reflects
  the updated args.

This means you usually do **not** need a manual `KeyedSubtree` in your story.

### Opt out of the default behavior

If you need to preserve local state across arg updates, override `setup` and
return the widget unchanged:

```dart title="counter.stories.dart"
final $Default = _Story(
  setup: (context, widget, args) => widget,
  args: _Args(
    initialValue: IntArg(10),
  ),
);
```

Use this only when keeping local state is intentional.

## Programmatic Arg Updates

You can programmatically update an arg's value from within a story using `arg.update(context, newValue)`.
This syncs the new value with the arg panel UI and URL query parameters, creating a two-way binding between widget interactions and arg controls.

A common use case is keeping the arg panel in sync when a user interacts with the widget itself, for example pressing a button that changes state.

### `BuilderArg`

Callback parameters (like `onChanged`, `onPressed`) need access to `BuildContext` to update args.
Use `BuilderArg` for this.
It takes a builder function that receives the context and returns the callback value:

```dart title="counter.stories.dart"
final $Default = _Story(
  args: _Args(
    onChanged: BuilderArg(
      (context) => (value) {
        final args = WidgetbookState.of(context).story!.args as _Args;
        args.initialValueArg.update(context, value);
      },
    ),
  ),
);
```

In this example, when the user taps the increment/decrement buttons in the `Counter` widget:

1. The widget calls `onChanged` with the new count.
2. The callback accesses the story's args via `WidgetbookState`.
3. `args.initialValueArg.update(context, value)` updates the `initialValue` arg panel to reflect the new value.

The result is that the arg panel stays in sync with widget interactions without any manual wiring.

<Info>
  `BuilderArg` values do not appear as interactive controls in the arg panel.
  They are context-dependent values that are resolved at build time.
</Info>

## Custom Args Source

The default source for args generation is the widget's constructor.
However, you can customize this behavior by providing a custom args class via `Meta.argsType` as follows:

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

part 'my_widget.stories.g.dart';

const meta = Meta(MyWidget.new, argsType: MyArgs.new);

class MyArgs {
  MyArgs({
    required this.number,
  });

  final int number;
}
```

After running the build runner, a custom `_Args` class will be generated based on your `MyArgs` class.
However, you will need to manually map the args in your story using the `builder` parameter:

```dart title="my_widget.stories.dart"
final $Custom = _Story(
  args: _Args(
    number: IntArg(10),
  ),
  builder: (context, args) {
    return MyWidget(
      title: 'Custom Title',
      isEnabled: true,
      count: args.number,
      status: MyStatus.inactive,
    );
  },
);
```

## Available Arg Types

Widgetbook offers first-class support for all primitive and common data types through various Arg classes:

| Type | Regular Arg | Nullable Arg |
| ---- | ----------- | ------------ |
| [bool](/args/boolean) | [BoolArg](/args/boolean#boolarg) | [NullableBoolArg](/args/boolean#nullableboolarg) |
| [int](/args/integer) | [IntArg](/args/integer#intarg-input) | [NullableIntArg](/args/integer#nullableintarg-input) |
| [double](/args/double) | [DoubleArg](/args/double#doublearg-input) | [NullableDoubleArg](/args/double#nullabledoublearg-input) |
| [String](/args/string) | [StringArg](/args/string#stringarg) | [NullableStringArg](/args/string#nullablestringarg) |
| [Duration](/args/duration) | [DurationArg](/args/duration#durationarg) | [NullableDurationArg](/args/duration#nullabledurationarg) |
| [DateTime](/args/datetime) | [DateTimeArg](/args/datetime#datetimearg) | [NullableDateTimeArg](/args/datetime#nullabledatetimearg) |
| [Color](/args/color) | [ColorArg](/args/color#colorarg) | [NullableColorArg](/args/color#nullablecolorarg) |
| [Enum](/args/enum) | [EnumArg](/args/enum#enumarg-dropdown) | [NullableEnumArg](/args/enum#nullableenumarg-dropdown) |
| [Custom](/args/custom) | Custom Arg | - |

## Fixed Args

In cases where you want to use a constant value that shouldn't be changeable in the Widgetbook UI, you can use the `Arg.fixed<T>` constructor.
This is useful for parameters that are not relevant for interactive tweaking.

```dart title="my_widget.stories.dart"
final $FixedExample = _Story(
  args: _Args(
    title: Arg.fixed('Fixed Title'),
    isEnabled: Arg.fixed(false),
    count: Arg.fixed(42),
  ),
);
```

If all the args are fixed, you can use the `_Args.fixed` constructor for brevity:

```dart title="my_widget.stories.dart"
final $AllFixed = _Story(
  args: _Args.fixed(
    title: 'Fixed Title',
    isEnabled: false,
    count: 42,
  ),
);
```

## Param-Arg Resolution

If you are wondering what type of arg will be generated based on your constructor parameter, here is a mapping.
`primitive.default` refers to the type's natural default (e.g., `false` for `bool`, `0` for `int`), while `param.default` refers to the default value specified in the constructor.

| Primitive | Nullable | Required | Default | Arg                                                 |
| --------- | -------- | -------- | ------- | --------------------------------------------------- |
| ✅        | ✅       | ✅       | ❌      | `Arg<Primitive>? = PrimitiveArg(primitive.default)` |
| ✅        | ✅       | ❌       | ✅      | `Arg<Primitive>? = PrimitiveArg(param.default)`     |
| ✅        | ✅       | ❌       | ❌      | `Arg<Primitive>? = PrimitiveArg(primitive.default)` |
| ✅        | ❌       | ✅       | ❌      | `Arg<Primitive> = PrimitiveArg(primitive.default)`  |
| ✅        | ❌       | ❌       | ✅      | `Arg<Primitive> = PrimitiveArg(param.default)`      |
| ❌        | ✅       | ✅       | ❌      | `Arg<Type>?`                                        |
| ❌        | ✅       | ❌       | ✅      | `Arg<Type>? = Arg.fixed(param.default)`             |
| ❌        | ✅       | ❌       | ❌      | `Arg<Type>?`                                        |
| ❌        | ❌       | ✅       | ❌      | `required Arg<Type>`                                |
| ❌        | ❌       | ❌       | ✅      | `Arg<Type> = Arg.fixed(param.default)`              |
