npx skills add ...
npx skills add dotnet/skills --skill plan-ui-change
Plan complex Blazor UI features by decomposing them into focused components. USE FOR: building a complex Blazor page with multiple sections, planning component decomposition, designing a multi-section dashboard or layout, breaking down a large UI feature into composable components, pages with sidebars and content panels, any page with 3+ distinct visual sections or multiple interacting sub-features, identifying parent-child relationships and data flow. DO NOT USE FOR: creating new Blazor projects or apps from scratch (use create-blazor-project), implementing a single individual component (use author-component), writing component code with parameters and EventCallback (use author-component), or simple single-component pages.
npx skills add dotnet/skills --skill plan-ui-change
When asked to build a complex UI feature, plan the component decomposition first, then immediately implement it. A single monolithic page component is almost never the right answer — break the UI into focused, composable components.
Read the request and identify every distinct visual region. Each region that has its own data, behavior, or layout responsibility is a candidate component.
Draw the component tree:
Rules for identifying components:
For every component in the tree, determine:
| Component | Action | Render Mode | State Owned | Lines (est.) |
|---|---|---|---|---|
| InventoryDashboard | Create | InteractiveServer | product list, filter state | ~80 |
| StockSummaryBar | Create | (inherits) | none — receives data | ~30 |
| InventoryFilters | Create | (inherits) | search text, selected category | ~60 |
| InventoryTable | Create | (inherits) | sort column, sort direction | ~50 |
| InventoryRow | Create | (inherits) | inline-edit mode flag | ~60 |
| AddProductForm | Create | (inherits) | form model | ~80 |
A page component that exceeds ~200 lines of combined markup + code is too large. If your estimate puts a single component above that, split further.
Identify the state owner for each piece of data, then map how it flows:
Rules:
[Parameter]EventCallback<T>Before creating a new component, check if an existing component in the project can serve the purpose. Look for:
DataTable<T>, Pagination) that accept templatesIf a component will be used in more than one page, place it in a Shared/ or Components/ folder.
Build bottom-up — leaf components first, then parents that compose them:
Each component should be independently compilable. Never reference a component that doesn't exist yet.
Present the plan briefly, then immediately proceed to implement — never stop at just the plan or ask for confirmation before writing code. The plan is a thinking tool, not a deliverable.
After outputting the plan, immediately begin implementing the components in the order listed. Do not wait for approval or ask "shall I proceed?" — the plan is a guide for you to follow, not a proposal for the user to approve.
| Anti-Pattern | Why It's Wrong | Correct Approach |
|---|---|---|
| One page component with 500+ lines | Impossible to test, reuse, or maintain | Decompose into focused components |
| Passing 10+ parameters through intermediate components | Parameter drilling obscures intent | Use cascading values or a scoped state service |
| Child component fetching its own data from an API | Multiple components making redundant calls | Parent owns data, passes via parameters |
| Inline rendering of list items with complex markup | Duplicated logic, no reuse, hard to test | Extract item template into its own component |
| Building everything in one file then "refactoring later" | Refactoring rarely happens; the monolith ships | Plan the decomposition upfront |
| Generic components for one-off usage | Over-engineering adds complexity | Only extract generics when reuse is proven |
.razor files — never stop at just the plan.ProductCard not ProductRenderer, OrderFilters not FilterHandler.InventoryDashboard (owns: products[], filters)
│
├─ [Parameter] products ──→ StockSummaryBar (reads aggregate stats)
│
├─ [Parameter] filters ──→ InventoryFilters
│ └─ EventCallback<Filters> OnFiltersChanged ──→ InventoryDashboard
│
├─ [Parameter] filteredProducts ──→ InventoryTable
│ └─ [Parameter] product ──→ InventoryRow
│ ├─ EventCallback<Product> OnSave ──→ InventoryTable ──→ InventoryDashboard
│ └─ EventCallback<Product> OnDelete ──→ InventoryTable ──→ InventoryDashboard
│
└─ EventCallback<Product> OnProductAdded ←── AddProductForm## Component Plan: [Feature Name]
### Component Tree
[ASCII tree showing parent-child relationships]
### Component Table
| Component | Action | Render Mode | Purpose | Est. Lines |
|-----------|--------|-------------|---------|------------|
| ... | ... | ... | ... | ... |
### Data Flow
[State owner] → [Parameters down] → [EventCallbacks up]
### Implementation Order
1. [First file to create — why]
2. [Second file — why]
...