Skip to content

🧩 Components & Widgets

Overview

Standards for creating reusable UI components and widgets in mobile applications.

🧩 Components & Widgets Location

Shared Components

  • shared/components/: put the global reusable components here.
  • for related components, create a sub folder and put the components there.

Feature Widgets

  • features/feature_name/presentation/widgets/: put the widgets specific to the feature here.
  • for related components, create a sub folder and put the components there.

Component Design Principles

  • Single Responsibility Principle
  • Composition over inheritance
  • Props/parameters validation
  • Consistent naming conventions

Best Practices

  • Create small, focused components
  • Prefer StatelessWidget unless local state is required.
  • Avoid deeply nested or rebuild-heavy widgets;extract parts into smaller widgets.
  • Keep build methods short (<100 lines).
  • Use const constructors and final fields whenever possible for performance.
  • Support light/dark themes if applicable.
  • Use named parameters for clarity.
  • Avoid rebuilding the whole screen for small state changes
  • Handle nulls gracefully; avoid ! operator.
  • Avoid side effects inside UI code.
  • Use the already defined custom components in the app insted of flutter's built-in components, like: AppText insted of Text, AppButton insted of ElevatedButton, etc.
  • make sure that the component supports both LTR and RTL layouts.
  • make sure that the component supports both dark and light themes.

Components Sub Folders

  • bottom_sheet/: Global usage bottom sheets should be added here.
  • buttons/: If you add any new general usage button component (not specific to a feature), add it here, if any of the already existing buttons are enough for your needs, use them instead of creating a new one.
  • date_and_time/: General usage date and time pickers or custom components should be added here.
  • dialogs/: General usage dialogs should be added here.
  • form_components/: General usage form components should be added here.

Examples

Good Example ✅

dart
// Good: Focused widget
class Button extends StatelessWidget {
  final Widget? child;
  final VoidCallback? onPressed;
  final Color? color;

  const Button({
    Key? key,
    this.child,
    this.onPressed,
    this.color,
  }) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return ElevatedButton(
      onPressed: onPressed,
      style: ElevatedButton.styleFrom(backgroundColor: color),
      child: child,
    );
  }
}

Bad Example ❌

dart
// Bad: Overly complex widget with too many responsibilities
class ComplexWidget extends StatelessWidget {
  final bool isLoading;
  final List<String> data;
  final String errorMessage;

  const ComplexWidget({
    Key? key,
    required this.isLoading,
    required this.data,
    required this.errorMessage,
  }) : super(key: key);

  @override
  Widget build(BuildContext context) {
    if (isLoading) {
      return const CircularProgressIndicator();
    } else if (errorMessage.isNotEmpty) {
      return Text('Error: $errorMessage');
    } else {
      return ListView.builder(
        itemCount: data.length,
        itemBuilder: (context, index) {
          return ListTile(title: Text(data[index]));
        },
      );
    }
  }
}