← Back to Component Index

Blazor Widget Alignment

Readiness map for aligning the draft Blazor home page on branch feature/aa/Blazor-Widget-Page (scaffolded before the design landed) with this component library + domain controls. Documentation only — the branch is not modified here.

Branch: feature/aa/Blazor-Widget-Page Updated: 2026-06-05 Audited: 2026-06-26

⚠ Reclassification: SingleButtonLarge is a content card, not a button

In Components/Widget.razor the SingleButtonLarge case renders a MudCard with an image banner (160px) + title + blurb — a content card, used for the "Hotel Request" item. The real buttons (SingleButton1, EmergencyButton) render MudButton. So despite the name, it maps to our Card / CardHero (the Document Hero domain control), not Button. Rename it during alignment (e.g. FeatureCard / HeroCard).

1. The shape already fits — it just needs the right names

The draft is a dynamic-widget system: a flat WidgetDto (with a string Type) is fed by IWidgetApiService and rendered by a single Widget.razor that switches on WidgetType. That is compatible with this architecture once reframed:

2. WidgetType → component / domain-control map

From Components/WidgetType.cs + the render cases in Components/Widget.razor:

Blazor WidgetTypeRenders (Blazor)Our scaffoldDomain controlAlignment note
PilotCardMudCard: title + linkCard (Chevron)Pilot Card✓ aligned — name matches
SingleButton1MudButton (icon + cta)Buttonicon button → Button
SingleButton2MudCard tile: icon + ctaButton (icon tile)tappable tile → Button (Icon variant)
SingleButtonLargeMudCard: image 160 + title + blurbCardHeroDocument Hero⚠ RECLASSIFY — a content card, not a button (see callout)
ThreeUpButtonMudPaper: 3× icon + labelButton Group3-up → Button Group
SliderImagesslider of media + eyebrow + title + blurb cardsCarouselHome Feed Carouselwith-images variant
SliderNoImagesslider, no mediaCarouselHome Feed Carouselno-images variant
SliderNoImagesEyebrowsslider, no media + eyebrowsCarouselHome Feed Carouselno-images + eyebrow variant
EmergencyButtonMudButton (emergency)ButtonEmergency Hotlinetel: action → Button

Net: 3 of the 9 WidgetTypes are Buttons (SingleButton1/2, EmergencyButton), 3 are a Carousel (the Slider* trio = Carousel variants), 1 is a Button Group (ThreeUpButton), 1 is a Card (PilotCard), and 1 is a content card mislabeled as a button (SingleButtonLarge).

3. WidgetDtoRawRepresentationFactory

D39 rename (2026-06-26): WidgetDto has been renamed to ItemDto and WidgetComponentFactory to ItemComponentFactory. The Type discriminator is now ItemType and the Background field is now BackgroundToken. This section describes the pre-rename codebase structure being refactored. See D39.

ApiModels/WidgetDto.cs is a flat catch-all (a string Type + every possible field: Title/Blurb/Cta/Icon/ThreeUpButtons/Slider*). Under D11 that DTO is the raw representation; a factory keyed on Type projects it onto the right typed scaffold ViewModel:

// WidgetDto (raw) -> scaffold ViewModel, dispatched by Type
public sealed class WidgetFactory : RawRepresentationFactory<ComponentViewModel>
{
    public ComponentViewModel Create(WidgetDto w) => w.Type switch
    {
        "PilotCard"         => pilotCardFactory.Create(...),                 // CardViewModel
        "SingleButtonLarge" => documentHeroFactory.Create(w),               // CardHeroViewModel (content card)
        "SingleButton1" or "SingleButton2" or "EmergencyButton"
                            => buttonFactory.Create(w),                      // ButtonViewModel
        "ThreeUpButton"     => buttonGroupFactory.Create(w.ThreeUpButtons), // ButtonGroupViewModel
        "SliderImages" or "SliderNoImages" or "SliderNoImagesEyebrows"
                            => feedCarouselFactory.Create(w.SliderItems),    // CarouselViewModel
        _ => throw new NotSupportedException(w.Type),
    };
}

Field reconciliation for the reclassified card: SingleButtonLargeCardHeroViewModel with Title → Title, Blurb → Description, Icon → Image. Keyed services (.NET 8+) can resolve the per-type factory by key instead of the switch.

4. Gaps & reconciliation for the alignment task

5. Branch files in scope

FileRole
Components/WidgetType.csthe 9-value enum (taxonomy to reconcile)
ApiModels/WidgetDto.csflat raw DTO → split via factory
Components/Widget.razor (+ .razor.cs)the mega-switch renderer → scaffold components
Components/Pages/DynamicWidgets.razorfeed renderer (host)
Services/IWidgetApiService.cs · MockWidgetApiService.csdata service (async gather — keep here)
Pages/BlazorPage.xaml (+ .cs) · wwwroot/css/widget.cssMAUI host + styling