home / skills / hoangnguyen0403 / agent-skills-standard / widgets

widgets skill

/skills/flutter/widgets

This skill guides building reusable, performant Flutter UI components with best practices for state, composition, theming, and layout.

npx playbooks add skill hoangnguyen0403/agent-skills-standard --skill widgets

Review the files below or copy the command above to add this skill to your agents.

Files (1)
SKILL.md
1.4 KB
---
name: Flutter UI Widgets
description: Principles for maintainable UI components.
metadata:
  labels: [ui, widgets]
  triggers:
    files: ['**_page.dart', '**_screen.dart', '**/widgets/**']
    keywords: [StatelessWidget, const, Theme, ListView]
---

# UI & Widgets

## **Priority: P1 (OPERATIONAL)**

Standards for building reusable, performant Flutter widgets and UI components.

- **State**: Use `StatelessWidget` by default. `StatefulWidget` only for local state/controllers.
- **Composition**: Extract UI into small, atomic `const` widgets.
- **Theming**: Use `Theme.of(context)`. No hardcoded colors.
- **Layout**: Use `Flex` + `Gap/SizedBox`.
- **Widget Keys**: All interactive elements must use keys from `widget_keys.dart`.
- **File Size**: If a UI file exceeds ~80 lines, extract sub-widgets into private classes.
- **Specialized**:
  - `SelectionArea`: For multi-widget text selection.
  - `InteractiveViewer`: For zoom/pan.
  - `ListWheelScrollView`: For pickers.
  - `IntrinsicWidth/Height`: Avoid unless strictly required.
- **Large Lists**: Always use `ListView.builder`.

```dart
class AppButton extends StatelessWidget {
  final String label;
  final VoidCallback onPressed;
  const AppButton({super.key, required this.label, required this.onPressed});

  @override
  Widget build(BuildContext context) => ElevatedButton(onPressed: onPressed, child: Text(label));
}
```

## Related Topics

performance | testing

Overview

This skill documents principles for building maintainable, reusable, and performant Flutter UI widgets. It focuses on clear state ownership, small atomic components, theming consistency, and practical layout and list strategies to keep codebases predictable and testable.

How this skill works

The guidance inspects common widget patterns and enforces defaults: prefer StatelessWidget, extract UI into const sub-widgets, and avoid hardcoded colors by using Theme.of(context). It also prescribes layout primitives, keys for interactive elements, file-size thresholds for extraction, and recommended widgets for selection, zooming, and large lists.

When to use it

  • When creating new Flutter UI components or screens.
  • When refactoring large or hard-to-test widget files.
  • When enforcing consistent theming and color usage across the app.
  • When implementing lists, pickers, or interactive views that need performance tuning.
  • When adding interactive elements that require stable identity and testing hooks.

Best practices

  • Prefer StatelessWidget by default; use StatefulWidget only for local state or controllers.
  • Extract UI into small, atomic const widgets and private classes when files exceed ~80 lines.
  • Use Theme.of(context) and avoid hardcoded colors to keep theming consistent.
  • Use Flex, Gap, and SizedBox for predictable layouts; avoid IntrinsicWidth/Height unless necessary.
  • Assign keys for all interactive elements using a centralized widget_keys.dart to ensure stability and testability.
  • Use ListView.builder for large or dynamic lists to preserve performance and memory.

Example use cases

  • Building a reusable AppButton as a StatelessWidget with const constructors and Theme-driven styles.
  • Refactoring a 200-line widget file into multiple private const sub-widgets to improve readability and testability.
  • Implementing a zoomable product image with InteractiveViewer and text selection across multiple widgets with SelectionArea.
  • Creating a picker UI using ListWheelScrollView for native-like selection behavior.
  • Replacing IntrinsicHeight usage with Flex + SizedBox to resolve expensive layout passes.

FAQ

When should I use StatefulWidget?

Use StatefulWidget only when the widget needs to own local mutable state or controllers that cannot be lifted to a parent or a state management solution.

Why avoid hardcoded colors?

Hardcoded colors break theming and dark mode. Using Theme.of(context) keeps styling consistent and easier to update app-wide.