Skills

Coordinate Components

Share state between components that don't have a direct parent-child parameter...

Install

npx skills add dotnet/skills --skill coordinate-components -g -a claude-code -y
Repository
dotnet/skills5.8k
Category
Design
Updated
3d ago
License
MIT
Context cost
Mediumabout 2,217 tokens
Runs scripts
No, instructions only

What it does

Share state between components that don't have a direct parent-child parameter relationship, using cascading values, scoped services with change events, or CascadingValueSource via DI. USE WHEN the user needs a CascadingParameter or CascadingValue that works across render mode boundaries, a shopping cart or notification count accessible from multiple pages, a theme or user preference cascaded app-wide, or when components in different parts of the tree must react when shared data changes. Also USE WHEN cascading values aren't reaching interactive children in per-page interactivity mode, or when the user needs to understand scoped vs singleton service lifetime for state on Blazor Server. DO NOT USE for direct parent-child parameter passing or EventCallback (see author-component), for persisting state across prerender-to-interactive transitions (see support-prerendering), or for service abstractions for data fetching in Auto/WebAssembly (see fetch-and-send-data).

Coordinate Components

Step 1, Read AGENTS.md

Read AGENTS.md at the workspace root to learn the project's conventions before making changes.

Step 2, Decide the scope

NeedMechanismWhen to use
Subtree (same render mode)CascadingValue componentTheme, layout config within a layout
App-wide (all render modes)CascadingValueSource<T> via DICurrent user, feature flags, theme shared globally
Mutable shared state within a circuitScoped service + Action eventShopping cart, notification count, selected filters

For parent→child one level: use [Parameter] / EventCallback (see author-component skill). For persisting state across prerender→interactive: see support-prerendering skill.

Workflow (quick reference)

  1. Choose the mechanism from the table in Step 2
  2. If crossing render mode boundaries → use CascadingValueSource<T> (Step 4)
  3. Register in Program.cs with AddCascadingValue(...) and isFixed: false
  4. Consume via [CascadingParameter] in child components
  5. Update via NotifyChangedAsync(newValue), never page reload
  6. For additional mutable state within a circuit → add scoped service (Step 5)
  7. Wrap any StateHasChanged from background threads in InvokeAsync
  8. Implement IDisposable, dispose timers, cancel tokens, unsubscribe events

Step 3, CascadingValue for subtree state

Wrap a subtree with <CascadingValue> to flow data to all descendants without passing it through every intermediate component.

@* In a layout or parent component *@
<CascadingValue Value="theme">
    @Body
</CascadingValue>

@code {
    private ThemeInfo theme = new() { ButtonClass = "btn-primary" };
}

Consume in any descendant:

[CascadingParameter]
private ThemeInfo? Theme { get; set; }
Read the whole SKILL.md on GitHub

More in Design