WebFormsPage

May 8, 2026 · View on GitHub

The WebFormsPage component is a unified legacy support wrapper that combines naming container and theming support into a single component. It also composes the lightweight <Page /> head renderer by default, so layout-level page metadata flows through the same shared page shim used by converted page code-behind.

Place WebFormsPage in your layout to give all pages automatic ID mangling (naming container) and theme/skin support without per-page configuration.

Background

In ASP.NET Web Forms, the Page class provided several structural services to all controls on the page:

  1. Naming Container — The page was the root INamingContainer, generating fully-qualified client IDs like ctl00_MainContent_MyButton
  2. Theme Application — The <%@ Page Theme="..." %> directive applied skin files to all controls
  3. Page head rendering — The page owned the document title and related metadata
  4. ViewState — The page serialized control state to a hidden field (not replicated — Blazor preserves state in component fields)

WebFormsPage combines naming, theming, and optional page-head rendering into a single Blazor component.

Features Supported in Blazor

  • Naming Container — Cascades naming scope to child components, prefixing IDs with the container's ID
  • UseCtl00Prefix — Optionally prepends ctl00 to the naming hierarchy for full Web Forms ID compatibility
  • Theme Cascading — Passes a ThemeConfiguration to all child styled components via CascadingValue
  • Page Head Rendering — Renders <Page /> by default so Title, MetaDescription, and MetaKeywords flow to <PageTitle> and <meta> tags
  • Visible — Controls whether child content renders (inherited from BaseWebFormsComponent)

Blazor Notes

WebFormsPage inherits from NamingContainer and composes ThemeProvider behavior. Both standalone components remain available for use independently when you only need one capability.

Usage

Place WebFormsPage in your MainLayout.razor wrapping @Body:

@inherits LayoutComponentBase

<WebFormsPage ID="MainContent" UseCtl00Prefix="true" Theme="@_theme">
    @Body
</WebFormsPage>

@code {
    private ThemeConfiguration _theme = new();
}

This mirrors how <form runat="server"> wrapped all page content in Web Forms. Every page automatically gets naming scope, theming, and page-head rendering.

Per-Page Usage

For area-specific configuration (e.g., different themes per section):

@page "/admin"

<WebFormsPage ID="AdminContent" Theme="@_adminTheme">
    <GridView DataSource="@data" AutoGenerateColumns="true" />
</WebFormsPage>

@code {
    private ThemeConfiguration _adminTheme = new();
}

Naming Only (No Theme)

When you only need ID mangling, omit the Theme parameter:

<WebFormsPage ID="MainContent" UseCtl00Prefix="true">
    <Button ID="Submit" Text="Save" />
    @* Button gets id="ctl00_MainContent_Submit" *@
</WebFormsPage>

With Theme Configuration

@using BlazorWebFormsComponents.Theming

<WebFormsPage ID="MainContent" Theme="@_theme">
    <Label Text="Themed label" />
    <Button ID="Save" Text="Save" />
</WebFormsPage>

@code {
    private ThemeConfiguration _theme;

    protected override void OnInitialized()
    {
        _theme = new ThemeConfiguration();
        _theme.AddSkin("Label", new ControlSkin { BackColor = WebColor.LightBlue });
        _theme.AddSkin("Button", new ControlSkin { BackColor = WebColor.Green, ForeColor = WebColor.White });
    }
}

Parameters

ParameterTypeDefaultDescription
IDstringnullSets the naming scope prefix for child component IDs
UseCtl00PrefixboolfalseWhen true, prepends ctl00 to the naming hierarchy
ThemeThemeConfigurationnullTheme configuration to cascade to child components
RenderPageHeadbooltrueWhen true, renders the shared <Page /> head component before page content
VisiblebooltrueControls whether child content renders
ChildContentRenderFragmentThe page content

Relationship to Other Components

ComponentPurposeWhen to Use
WebFormsPageCombined naming + theming + optional head renderingLayout-level wrapper for full legacy support
NamingContainerNaming scope onlyWhen you need nested naming scopes within a page
ThemeProviderTheme cascading onlyWhen demonstrating theming in isolation
PageHead rendering onlyWhen you need document title/meta rendering without the layout wrapper

IsPostBack Property

The WebFormsPageBase class provides an IsPostBack property for Web Forms compatibility:

public bool IsPostBack => false;  // Always false in page context

Important: IsPostBack always returns false at the page level because Blazor pages don't have HTTP postback semantics. For component-level postback detection (in SSR or interactive modes), use IsPostBack on BaseWebFormsComponent instead.

For page-level initialization patterns, use the Blazor lifecycle directly:

@inherits WebFormsPageBase

@code {
    protected override void OnInitialized()
    {
        // Replaces if (!IsPostBack) pattern
        LoadInitialData();
    }
}

Moving On

As you refactor away from Web Forms patterns:

  1. ID Mangling — Consider using Blazor's built-in @ref instead of string-based IDs for element references
  2. Theming — Consider migrating to CSS custom properties or a CSS framework for theming
  3. ViewState — Blazor preserves component state automatically in component fields; no hidden field serialization needed
  4. Form Patterns — For forms that need postback-like behavior in SSR, use ViewState and IsPostBack on components (see ViewStateAndPostBack.md)

See Also