Skip to content

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

Step 1: Generate a UI Component

bash
archipelago generate ui_kit_component

You will be prompted for:

  • componentName — e.g., button, card, dialog
  • atomicTypeatom, molecule, or template
  • widgetTypestateless or stateful
  • prefix — e.g., App, My (your UI Kit prefix)
  • appNameMyApp
  • hasVariantstrue for style variants (primary, secondary, etc.)
  • hasSizestrue for size variants (sm, md, lg)
  • hasTypestrue for 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 implementation

Step 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

CustomizationWhere to Change
Add variants*_variant.dart enum + style resolver
Add sizes*_size.dart enum + style resolver
Change widget typeRegenerate with different widgetType
Custom animationsHeadless base widget
Theme integrationstyled/ implementation

Next Steps

Built by Banua Coder