widget-composition

Enforces Flutter widget composition rules for const widget classes, lean build methods, and structural layout.

Updated Aug 22, 2026
One-click install
npx skills add https://github.com/zakariaf/NearlyStop --skill widget-composition-zakariaf
Or copy as Structured Prompt for Agent
Please help me install this Agent Skill.
Skill: widget-composition
Source: https://github.com/zakariaf/NearlyStop/tree/main/.claude/skills/widget-composition
Command: npx skills add https://github.com/zakariaf/NearlyStop --skill widget-composition-zakariaf

SYSTEM DOCUMENTATION & REQUIREMENTS

💡 This Skill includes scripts (resource) and references (resource) components.

What problem does it solve? Flutter screens built with Widget _buildX() helper methods, god-widgets, and logic-heavy build() methods rebuild unnecessarily, resist testing, and hide RTL, keyboard, and accessibility bugs that surface only in production. ## Core Features & Use Cases - Composition rules: Mandates extracting named const widget classes over helper methods, keeping build() under 80 lines, and keeping I/O, formatting, and domain math out of the widget layer. - Structural layout guidance: Covers full-bleed backgrounds vs SafeArea content, computed cell sizing, the GridView cross/main-axis spacing trap, directional insets, and IME/resizeToAvoidBottomInset handling. - Lint script: Ships scripts/check-widget-composition.sh, a grep-based checker that flags _buildX() methods, GlobalKey, eager ListViews, DateTime.now() in widgets, hardcoded left/right insets, and text-scaler clamps before a PR. - Use Case: When refactoring a 300-line Flutter screen, apply this Skill to split it into small const widget classes, move formatting into the Riverpod Notifier, add ValueKeys to the reorderable list, and verify with the check script. ## Quick Start Ask the AI to review or refactor a Flutter screen using the widget-composition rules and run scripts/check-widget-composition.sh on the lib directory.

Frequently Asked Questions about widget-composition

High-intent search queries and answers about installing and using this skill.

FAQPage Schema
Why extract a Flutter widget class instead of a _buildX() helper method?

A helper method's subtree has no Element of its own, so it rebuilds with the parent, cannot be const, cannot take a Key, and cannot be found with find.byType in tests. A widget class gets its own Element boundary, enabling const canonicalization, keyed identity, and isolated testing.

How do I keep Flutter build() methods small and fast?

Keep build() under roughly 80 lines with nesting at or below five levels, and extract complex sections into separate widget classes. Move I/O, DateTime.now(), NumberFormat, and domain math into the Notifier, which precomputes ready-to-render UI state the widget only paints.

When should I use ValueKey vs GlobalKey in Flutter lists?

Use ValueKey(item.id) for rows in reorderable, filterable, or variable-length lists so Element state tracks data identity rather than position. Fixed-order stateless lists need no key, and GlobalKey for identity or lookups is a design smell — lift that state to the ViewModel instead.

What is the GridView crossAxisSpacing vs mainAxisSpacing trap?

In a vertical GridView, crossAxisSpacing is the gap between columns and mainAxisSpacing is the gap between rows, which is counter-intuitive. Swapping them silently exchanges horizontal and vertical gutters, visible only when the design uses unequal spacing.

Should a Flutter widget read MediaQuery or app state for accessibility settings?

Read platform accessibility state like bold text, high contrast, and text scale directly from MediaQuery at build time, since it is an InheritedWidget with correct invalidation. Never mirror it into a provider and never clamp textScaler — fix the layout to survive scaling instead.

When is a StatefulWidget appropriate in Flutter?

Use StatefulWidget only for genuinely local, ephemeral UI state such as AnimationController, TextEditingController, ScrollController, or FocusNode. App, domain, and session state belongs in a Notifier, and every controller created in State must be disposed in dispose().