Creating a UI Kit Component
What you'll learn
- Scaffolding a headless UI component with styled implementation
- Configuring variants, sizes, and types for your component
- Understanding the atomic design categorization
- Customizing generated component styles
Prerequisites
- An existing Archipelago monorepo (see Monorepo Scaffolding)
- UI Kit already generated (see UI Kit Setup)
Step 1: Generate a UI Component
bash
archipelago generate ui_kit_componentYou will be prompted for:
- componentName — e.g.,
button,card,dialog - atomicType —
atom,molecule, ortemplate - widgetType —
statelessorstateful - prefix — e.g.,
App,My(your UI Kit prefix) - appName —
MyApp - hasVariants —
truefor style variants (primary, secondary, etc.) - hasSizes —
truefor size variants (sm, md, lg) - hasTypes —
truefor type variants (filled, outline, ghost)
Or use a config file:
json
{
"componentName": "button",
"atomicType": "atom",
"widgetType": "stateful",
"prefix": "App",
"appName": "MyApp",
"hasVariants": true,
"hasSizes": true,
"hasTypes": true
}Step 2: Understand the Generated Structure
ui_kit/
└── lib/src/
└── atoms/
└── button/
├── app_button.dart # Headless base widget
├── app_button_style.dart # Style contract
├── app_button_variant.dart # Variant enum (primary, secondary...)
├── app_button_size.dart # Size enum (sm, md, lg)
├── app_button_type.dart # Type enum (filled, outline, ghost)
└── styled/
└── styled_app_button.dart # Default styled implementationStep 3: The Headless Pattern
The generated component separates logic from styling. The headless base widget handles behavior (tap, focus, state), while styled implementations provide the visual layer:
dart
// Headless base — handles logic only
class AppButton extends StatefulWidget {
final VoidCallback? onPressed;
final Widget child;
final AppButtonVariant variant;
final AppButtonSize size;
// No styling here — just behavior
}
// Styled implementation — provides visuals
class StyledAppButton extends StatelessWidget {
@override
Widget build(BuildContext context) {
final style = theme.buttonStyleFor(variant, size, type);
return AppButton(
// Applies theme-driven styles
);
}
}Step 4: Use the Component
dart
import 'package:ui_kit/ui_kit.dart';
StyledAppButton(
variant: AppButtonVariant.primary,
size: AppButtonSize.md,
type: AppButtonType.filled,
onPressed: () => doSomething(),
child: Text('Submit'),
)Step 5: Add a Custom Variant
Edit the variant enum and add styling:
dart
// app_button_variant.dart
enum AppButtonVariant { primary, secondary, danger, success }Then update the style resolver to handle the new variant.
Common Customizations
| Customization | Where to Change |
|---|---|
| Add variants | *_variant.dart enum + style resolver |
| Add sizes | *_size.dart enum + style resolver |
| Change widget type | Regenerate with different widgetType |
| Custom animations | Headless base widget |
| Theme integration | styled/ implementation |
Next Steps
- Add a theme variant to style components differently
- Use the UI Kit Generator CLI for batch scaffolding