C# Academy · Lesson

Blazor Component Model

Create Razor components, understand the component lifecycle, use parameters and cascading values.

Lesson 1 of 413 steps

Blazor Component Model is a free C# Academy lesson on CoddyKit. This is lesson 1 of 4. You can read the complete lesson below for free — then practise it hands-on in the browser with a built-in code editor and a 24/7 AI tutor. It is part of the C# Academy learning path, and your progress syncs across the web and the CoddyKit app. The C# Academy course includes 4 lessons in total.

What Is Blazor?

Blazor lets you build interactive web UIs using C# instead of JavaScript. Components are defined in .razor files combining HTML markup and C# logic. Blazor runs on the server (Blazor Server) or in the browser via WebAssembly (Blazor WASM).

Your First Component

A Razor component is a .razor file with HTML markup and a @code block for C#. The component name becomes the HTML tag name.

@* Greeting.razor *@
<h2>Hello, @Name!</h2>
<p>You have @Count messages.</p>

@code {
    [Parameter] public string Name { get; set; } = "World";
    private int Count = 5;
}

Component Lifecycle

Blazor components have a lifecycle with hooks you can override. The most common ones are OnInitializedAsync (data loading) and OnParametersSetAsync (reacting to parameter changes).

@code {
    private List<Product> Products = new();

    protected override async Task OnInitializedAsync()
    {
        // Called once on first render
        Products = await Http.GetFromJsonAsync<List<Product>>("/api/products")
                   ?? new();
    }

    protected override async Task OnParametersSetAsync()
    {
        // Called whenever parameters change
        await LoadDataAsync();
    }
}

Parameters: Passing Data to Components

Decorate properties with [Parameter] to accept data from parent components. Parameters are set before render and can trigger re-render when changed.

@* ProductCard.razor *@
<div class="card">
    <h4>@Product.Name</h4>
    <p>Price: @Product.Price.ToString("C")</p>
    <button @onclick="AddToCart">Add to Cart</button>
</div>

@code {
    [Parameter, EditorRequired]
    public Product Product { get; set; } = default!;

    [Parameter]
    public EventCallback<Product> OnAddToCart { get; set; }

    private async Task AddToCart() =>
        await OnAddToCart.InvokeAsync(Product);
}

Cascading Parameters

Cascading parameters flow down the component tree without explicit passing through every intermediate level — ideal for themes, user info, or shared state.

@* App.razor — wraps the whole app *@
<CascadingValue Value="CurrentUser">
    <Router AppAssembly="@typeof(App).Assembly">
        <Found Context="routeData">
            <RouteView RouteData="routeData" DefaultLayout="@typeof(MainLayout)" />
        </Found>
    </Router>
</CascadingValue>

@* Anywhere in the tree: *@
@code {
    [CascadingParameter]
    public UserInfo CurrentUser { get; set; } = default!;
}

Rendering Lists and Conditionals

Use Razor directives @if, @foreach, and @for to render dynamic content. Always provide @key on list items for efficient diffing.

@if (Products.Count == 0)
{
    <p>No products found.</p>
}
else
{
    <ul>
        @foreach (var product in Products)
        {
            <li @key="product.Id">
                <ProductCard Product="product" OnAddToCart="HandleAdd" />
            </li>
        }
    </ul>
}

RenderFragment and ChildContent

Use RenderFragment to pass markup as a parameter — like slots in Vue or children in React. The conventional parameter name is ChildContent.

@* Panel.razor *@
<div class="panel">
    <div class="panel-header">@Title</div>
    <div class="panel-body">@ChildContent</div>
</div>

@code {
    [Parameter] public string Title { get; set; } = "";
    [Parameter] public RenderFragment? ChildContent { get; set; }
}

@* Usage: *@
<Panel Title="Order Details">
    <p>Order #42 — Shipped</p>
</Panel>

Component References with @ref

Capture a reference to a child component with @ref to call its public methods or read its properties from the parent.

@* Parent.razor *@
<ConfirmDialog @ref="_dialog" OnConfirm="DeleteOrder" />
<button @onclick="() => _dialog!.Show()">Delete Order</button>

@code {
    private ConfirmDialog? _dialog;

    private async Task DeleteOrder()
    {
        await OrderService.DeleteAsync(CurrentOrderId);
        // Refresh UI...
    }
}

StateHasChanged and Manual Re-Rendering

Blazor automatically re-renders after event handlers. For async state changes outside event handlers (e.g., from a background timer), call StateHasChanged() manually.

@implements IDisposable

<p>Time: @CurrentTime</p>

@code {
    private string CurrentTime = "";
    private Timer? _timer;

    protected override void OnInitialized()
    {
        _timer = new Timer(_ =>
        {
            CurrentTime = DateTime.Now.ToString("HH:mm:ss");
            InvokeAsync(StateHasChanged); // thread-safe re-render
        }, null, 0, 1000);
    }

    public void Dispose() => _timer?.Dispose();
}

ShouldRender for Performance

Override ShouldRender() to skip unnecessary re-renders. Return false when the component's output won't change, reducing diffing overhead.

@code {
    private string _lastRenderedStatus = "";

    [Parameter] public string Status { get; set; } = "";

    protected override bool ShouldRender()
    {
        // Only re-render if Status actually changed
        if (Status == _lastRenderedStatus) return false;
        _lastRenderedStatus = Status;
        return true;
    }
}

Real-World: Product Listing Component

A complete product listing component that loads data on initialization, handles loading state, and passes events to the parent.

@inject HttpClient Http

@if (_loading)
{
    <p>Loading products...</p>
}
else
{
    @foreach (var p in _products)
    {
        <ProductCard Product="p" OnAddToCart="AddToCart" />
    }
}

@code {
    private List<Product> _products = new();
    private bool _loading = true;

    [Parameter] public EventCallback<Product> OnCartUpdated { get; set; }

    protected override async Task OnInitializedAsync()
    {
        _products = await Http.GetFromJsonAsync<List<Product>>("/api/products")
                   ?? new();
        _loading = false;
    }

    private async Task AddToCart(Product p) => await OnCartUpdated.InvokeAsync(p);
}

Quick Check

Which lifecycle method is the best place to load data from an API when a Blazor component initializes?

Recap: Blazor Component Model

Key takeaways:

  • .razor files mix HTML markup with C# in an @code block
  • [Parameter] accepts data from parent; EventCallback passes events up
  • CascadingParameter flows data down without prop-drilling
  • RenderFragment/ChildContent creates composable slot-based components
  • OnInitializedAsync for initial data load; StateHasChanged for manual re-render
  • ShouldRender() skips unnecessary diffing for performance
Free to start

Learn C# with an AI tutor — free

Write and run real code in your browser, get instant help from a 24/7 AI tutor, and pick up where you left off on the web or in the app.

Courses
93
Lessons
346

Frequently Asked Questions

Is the “Blazor Component Model” lesson free?

Yes — the full text of “Blazor Component Model” is free to read here on the web. To practise it interactively (a built-in code editor and a 24/7 AI tutor) and unlock the rest of the C# Academy course, upgrade to CoddyKit PRO. The C# Academy course includes 4 lessons in total.

What will I learn in “Blazor Component Model”?

Create Razor components, understand the component lifecycle, use parameters and cascading values. You practise C# Academy with hands-on code you run directly in the browser, and a 24/7 AI tutor answers your questions as you work through the lesson.

Do I need any experience to start C# Academy?

No prior experience is required. C# Academy on CoddyKit is structured for beginners through advanced learners, so you can start here or from the beginning and move at your own pace. This is lesson 1 of 4.

How long does the “Blazor Component Model” lesson take?

Most CoddyKit lessons take about 5–10 minutes. Each one is bite-sized and interactive, so you make steady progress and pick up exactly where you left off across the web and the app.

Can I write and run code in this C# Academy lesson?

Yes. Every C# Academy lesson includes a built-in code editor, so you write and run real code right in your browser and get instant AI feedback — no local setup required.

All lessons in this course

  1. Blazor Component Model
  2. Data Binding & Event Handling
  3. Component Communication & DI
  4. State Management in Blazor
← Back to C# Academy