Rabbit helps you create these wrapper widgets quickly and consistently, maintaining all the original widget's parameters while allowing you to customize what you need.
For example, given a Container
widget:
Container(
color: Colors.red,
child: child,
)
Generate a RedContainer
widget that encapsulates this styling and reuse it throughout your app:
RedContainer(
child: child,
)
- Rabbit
- Flutter 3.22.0 or later
Add Rabbit to your project's dependencies:
dart pub add rabbit
Or manually add it to your pubspec.yaml
:
dependencies:
rabbit: ^latest_version
Then run:
dart pub get
In this example we will generate a RedContainer
widget that is identical to a Container
widget but with a red background color.
-
Configure your widget wrappers in
pubspec.yaml
:rabbit: widgets: package:flutter/material.dart: - Container
For a complete list of configuration options, see the Configuration section.
-
Run the generation command:
dart run rabbit generate
This will generate a
$Container
widget in the default output directory.[!IMPORTANT] Rabbit does not handle imports perfectly. You may need to add or remove some imports manually.
However, any other syntax errors are considered bugs, and you should open an issue if you encounter them. -
Locate the generated widget and customize it as needed.
class RedContainer extends StatelessWidget { final AlignmentGeometry alignment; final EdgeInsetsGeometry padding; // ... and the rest of the Container properties const RedContainer({ super.key, this.alignment, this.padding, // ... and the rest of the Container properties }); @override Widget build(BuildContext context) { return Container( color: Colors.red, alignment: alignment, padding: padding, // ... and the rest of the Container properties ); } }
You can now use the
RedContainer
widget in your app as you would aContainer
widget. -
(Optional) Rename the generated file: Rename the generated file to
red_container.dart
for better readability and import statements.
Now you can use the RedContainer
widget in your app as you would a Container
widget.
RedContainer(
child: Text('Hello, World!'),
)
The following options can be configured in your pubspec.yaml
under the rabbit
key:
Option | Default | Description |
---|---|---|
widgets |
Required | Map of package imports and widget names |
output_dir |
lib/src/wrapped |
Directory where generated files will be placed |
prefix |
$ |
Prefix for generated widget names |
docs |
false |
Include documentation comments from original widget |
pipeable |
false |
Generate pipeable extensions for widgets |
rabbit:
output_dir: lib/src/widgets
prefix: My
docs: true
widgets:
package:flutter/material.dart:
- Container
- ElevatedButton
package:shadcn_ui/shadcn_ui.dart:
- ShadButton
The widgets
option is a map where:
- Keys are package import statements
- Values are lists of widget names to generate wrappers for
You can use the special value all
to generate wrappers for all widgets in a package:
rabbit:
widgets:
package:flutter/material.dart:
- all # Will generate wrappers for all Material widgets
all
will generate a large number of files and is not recommended for most use cases.
The directory where generated files will be placed.
rabbit:
output_dir: lib/src/widgets # Your custom path
- Default:
lib/src/wrapped
- The directory will be created if it doesn't exist
- Relative paths are resolved from your project root
- The generate widgets will match the package structure of the original widgets
The prefix added to generated widget names to avoid naming conflicts.
rabbit:
prefix: My # Will generate MyContainer, MyButton, etc.
- Default:
$
- Can be set to an empty string (
''
) if you want no prefix
Controls whether documentation comments from the original widget are included.
rabbit:
docs: true
- Default:
false
- Includes parameter descriptions, examples, and other documentation
- Can significantly increase the size of generated files
- Useful when creating public packages or maintaining API documentation
As an experimental feature, Rabbit can generate pipeable extensions for widgets. This allows you to chain widget properties using this operator (>>
) instead of nested constructors.
final widget = $Container()
>> $Padding(padding: EdgeInsets.all(16))
>>> Text('Hello, World!');
See this proposal which inspired this feature.
Recommended Usage
The following configuration generates pipeable extensions for the most common Flutter widgets. Feel free to customize this list to include only the widgets you use most often.
rabbit:
pipeable: true
docs: true
widgets:
package:flutter/material.dart:
- Directionality
- Opacity
- ClipRRect
- Transform
- Padding
- Align
- Center
- SizedBox
- ConstrainedBox
- FractionallySizedBox
- SliverToBoxAdapter
- Positioned
- PositionedDirectional
- Flexible
- Expanded
- TableCell
- GestureDetector
- DecoratedBox
- Container
- Hero
- Banner
- PreferredSize
- InkWell
- ElevatedButton
- FilledButton
- OutlinedButton
- TextButton
- FloatingActionButton
- Tab
- Card
- Dialog
When a widget has multiple constructors, Rabbit generates a separate wrapper for each constructor. For example, with ListView
:
// Original ListView has multiple constructors:
// ListView()
// ListView.builder()
// ListView.separated()
// ListView.custom()
// Rabbit will generate:
class $ListView extends StatelessWidget { ... }
class $ListViewBuilder extends StatelessWidget { ... }
class $ListViewSeparated extends StatelessWidget { ... }
class $ListViewCustom extends StatelessWidget { ... }
Each generated wrapper maintains the exact signature and functionality of its corresponding constructor.
- Does not support generating wrappers for widgets with private constructors
- Widgets with default values for parameters have those parameters as required in the generated code
- Does not generate imports for types without a prefix
If a Flutter update changes the API of wrapped widgets:
- Backup your customized wrappers
- Regenerate the wrappers with the latest Flutter version:
dart run rabbit generate
- Copy your customizations from the backup to the newly generated files
This ensures your wrappers stay in sync with Flutter's API changes while preserving your modifications.
Create consistent themed versions of widgets across your app:
class PrimaryButton extends StatelessWidget {
// Generated from ElevatedButton
// Customized with your theme's primary color
}
### Platform-Specific Variants
```dart
class AdaptiveContainer extends StatelessWidget {
// Generated from Container
// Customized with platform-specific styling
}
class LoadingButton extends StatelessWidget {
// Generated from ElevatedButton
// Adds loading state handling
}
- For consistent styling across your app
- When you need multiple variants of a widget
- To encapsulate complex behavior
- For one-off customizations
- When composition would be clearer
- For very simple modifications
- Use descriptive names that indicate the purpose
- Follow Flutter's widget naming conventions
- Consider grouping related wrappers
- Eww, why would you want to do this?
- Why didn't you do it this way?
- Why didn't you use blank instead?
- Why did you do it that way?
- This isn't working, who made this garbage?
You may have a good point, open an issue and let me know.