Blazor Tutorial for Beginners: Build Modern Web Apps with C# and .NET
Modern web development usually requires developers to work with several languages and frameworks. A typical application may use HTML and CSS for presentation, JavaScript or TypeScript for frontend behavior, and another language for backend development.
Blazor provides a different path for .NET developers.
With Blazor, you can build interactive web user interfaces using C#, Razor, HTML, and the .NET platform. This makes it especially interesting for developers who already know C# and want to build modern web applications without making JavaScript their primary application language.
This Blazor tutorial for beginners focuses on the concepts you need to understand before building larger applications. You will learn what Blazor is, how Razor components work, how to handle user interaction, pass data between components, create forms, use dependency injection, understand component lifecycle methods, and organize a small Blazor application.
The goal is not to memorize Blazor syntax. It is to understand the Blazor programming model well enough to start building your own applications.
What Is Blazor?
Blazor is a .NET web UI framework for building interactive web applications using C#.
The name comes from the combination of Browser and Razor.
Blazor applications are built from reusable Razor components. These components combine UI markup with C# code and typically use the .razor file extension.
A simple component might look like this:
<h3>Hello Blazor</h3>
<p>Welcome to my first Blazor component.</p>But components are not limited to static HTML.
They can contain:
C# code
Application state
Event handlers
Parameters
Forms
Validation
Dependency injection
Asynchronous operations
Reusable UI logic
This component-based model is one of the foundations of Blazor development.
Why Should C# Developers Learn Blazor?
One of Blazor's biggest advantages for .NET developers is familiarity.
If you already work with C#, ASP.NET Core, dependency injection, asynchronous programming, LINQ, and Entity Framework Core, many of your existing skills remain useful.
Instead of switching between completely different programming ecosystems for the frontend and backend, a Blazor solution can use C# across much of the application.
For example:
Blazor UI
↓
C#
↓
Application Services
↓
Entity Framework Core
↓
DatabaseThis does not mean that HTML, CSS, browser behavior, or JavaScript become irrelevant.
A professional Blazor developer should still understand web fundamentals. JavaScript interoperability is also available when browser APIs or JavaScript libraries are needed.
The important difference is that C# can remain the primary programming language for your interactive UI.
What Can You Build with Blazor?
Blazor can be used for many types of web applications.
Examples include:
Business management systems
Inventory applications
ERP systems
CRM applications
Administrative dashboards
Customer portals
Internal enterprise applications
Reporting systems
E-commerce interfaces
SaaS applications
Data-driven web applications
Blazor is particularly attractive when an organization already uses the .NET ecosystem and wants to reuse its C# skills across the application.
What Should You Know Before Learning Blazor?
Blazor can be approachable for C# developers, but several fundamentals will make learning much easier.
C#
You should understand:
Variables
Methods
Classes
Interfaces
Collections
Generics
LINQ
Dependency injection concepts
Async and await
You do not need advanced knowledge of every C# feature before starting.
HTML
Blazor components render web interfaces, so basic HTML knowledge is essential.
You should understand elements such as:
<h1>Heading</h1>
<p>Paragraph</p>
<input type="text">
<button>Save</button>CSS
CSS controls the appearance and layout of your application.
You should know the basics of:
Classes
Selectors
Spacing
Layout
Responsive design
ASP.NET Core Fundamentals
ASP.NET Core knowledge is helpful because Blazor is part of the .NET web development ecosystem.
Concepts such as dependency injection, configuration, authentication, logging, and application services will become increasingly important as your application grows.
Understanding Razor Components
A Blazor application is built from components.
A component is a reusable section of the user interface that can contain both markup and C# behavior.
Create a file called:
Welcome.razorThen add:
<h3>Welcome</h3>
<p>Hello from Blazor!</p>You can use the component elsewhere like an HTML element:
<Welcome />This is a fundamental Blazor concept.
Instead of building one enormous page, you can divide your interface into reusable pieces such as:
MainMenu
ProductCard
ProductList
ProductForm
CustomerForm
SalesSummary
StockStatusSmaller components are usually easier to understand, test, reuse, and maintain.
Adding C# Code to a Blazor Component
A Razor component can contain C# directly.
For example:
<h3>@title</h3>
<p>Current quantity: @quantity</p>
@code {
private string title = "Product Details";
private int quantity = 10;
}The @ symbol allows Razor to transition between markup and C#.
The @code block contains the component's C# members.
This ability to combine UI markup and C# logic is central to Blazor development.
Understanding Razor Syntax
Razor allows C# expressions to appear naturally inside markup.
For example:
<p>@productName</p>You can also use C# conditions:
@if (isAvailable)
{
<p>Product is available.</p>
}
else
{
<p>Product is out of stock.</p>
}And loops:
@foreach (var product in products)
{
<p>@product.Name</p>
}This makes it possible to generate UI based on your C# data.
Handling Button Clicks in Blazor
Interactive applications need to respond to user actions.
Blazor provides event directives for this purpose.
Consider a simple counter:
<h3>Counter</h3>
<p>Current count: @currentCount</p>
<button @onclick="IncrementCount">
Increase
</button>
@code {
private int currentCount;
private void IncrementCount()
{
currentCount++;
}
}When the button is clicked, Blazor calls IncrementCount().
The value changes, and Blazor updates the relevant part of the interface.
You do not need to manually manipulate the DOM to update the displayed count.
Passing Parameters to Components
Reusable components often need data from their parent components.
Blazor supports component parameters.
Suppose you create:
ProductCard.razorThe component could contain:
<div class="product-card">
<h3>@Name</h3>
<p>Price: @Price</p>
</div>
@code {
[Parameter]
public string Name { get; set; } = string.Empty;
[Parameter]
public decimal Price { get; set; }
}A parent component can then use it:
<ProductCard
Name="Laptop"
Price="75000" />This makes ProductCard reusable for different products.
Passing Events from Child to Parent Components
Sometimes a child component needs to inform its parent that something happened.
Blazor provides EventCallback for this scenario.
For example:
<button @onclick="SelectProduct">
Select
</button>
@code {
[Parameter]
public EventCallback OnSelected { get; set; }
private async Task SelectProduct()
{
await OnSelected.InvokeAsync();
}
}The parent can respond to the callback.
This pattern is useful when creating reusable buttons, dialogs, product cards, selectors, and form components.
Understanding Data Binding
Blazor supports data binding between UI elements and C# values.
Consider:
<input @bind="name" />
<p>Hello, @name</p>
@code {
private string name = string.Empty;
}When the user changes the input value, the C# property is updated.
The displayed text can then reflect the new value.
This is especially useful when building forms.
Building a Simple Product List
Let's create something slightly more practical.
First, define a model:
public class Product
{
public int Id { get; set; }
public string Name { get; set; } = string.Empty;
public decimal Price { get; set; }
public int StockQuantity { get; set; }
}Now create some sample products inside a component:
@foreach (var product in products)
{
<div>
<strong>@product.Name</strong>
<span>Price: @product.Price</span>
<span>Stock: @product.StockQuantity</span>
</div>
}
@code {
private List<Product> products = new()
{
new Product
{
Id = 1,
Name = "Laptop",
Price = 75000,
StockQuantity = 5
},
new Product
{
Id = 2,
Name = "Keyboard",
Price = 2500,
StockQuantity = 20
}
};
}Blazor loops through the C# collection and renders each product.
This is a basic example, but the same concept applies when the products come from a database or API.
Conditional Rendering in Blazor
Business applications frequently need to display different UI based on data.
For example:
@if (product.StockQuantity > 0)
{
<span>In Stock</span>
}
else
{
<span>Out of Stock</span>
}You could also display different controls depending on application state:
@if (isLoading)
{
<p>Loading...</p>
}
else
{
<ProductList />
}Conditional rendering is useful for:
Loading indicators
Permission-based controls
Empty states
Error messages
Stock status
Form states
Routing in Blazor
Blazor components can also represent pages.
A routable component uses the @page directive.
For example:
@page "/products"
<h1>Products</h1>Visiting /products displays this component.
You can also use route parameters:
@page "/products/{Id:int}"
<h1>Product Details</h1>
<p>Product ID: @Id</p>
@code {
[Parameter]
public int Id { get; set; }
}Now a URL such as:
/products/10provides 10 as the component's Id.
This is useful for details and edit pages.
Navigation in Blazor
Blazor provides NavLink for navigation links.
For example:
<NavLink href="/products">
Products
</NavLink>For navigation from C# code, you can use NavigationManager.
@inject NavigationManager Navigation
<button @onclick="GoToProducts">
View Products
</button>
@code {
private void GoToProducts()
{
Navigation.NavigateTo("/products");
}
}This allows navigation to be triggered by application logic.
Dependency Injection in Blazor
Dependency injection is an important part of .NET application development.
Suppose you have a service:
public interface IProductService
{
Task<List<Product>> GetProductsAsync();
}And an implementation:
public class ProductService : IProductService
{
public Task<List<Product>> GetProductsAsync()
{
// Retrieve products
return Task.FromResult(new List<Product>());
}
}Register it:
builder.Services.AddScoped<IProductService, ProductService>();Then inject it into a Razor component:
@inject IProductService ProductServiceNow the component can use the service without manually creating it.
This keeps UI components less dependent on infrastructure details.
Loading Data Asynchronously
Database and API operations are commonly asynchronous.
A Blazor component can load data asynchronously during its lifecycle.
For example:
@if (products is null)
{
<p>Loading products...</p>
}
else
{
@foreach (var product in products)
{
<p>@product.Name</p>
}
}
@code {
private List<Product>? products;
protected override async Task OnInitializedAsync()
{
products = await ProductService.GetProductsAsync();
}
}OnInitializedAsync() is called as the component is initialized.
This is a common place to load initial component data when that data doesn't depend on parameters changing later.
Understanding the Blazor Component Lifecycle
Blazor components have lifecycle methods that run at different stages.
Some commonly encountered methods include:
OnInitialized
OnInitializedAsync
OnParametersSet
OnParametersSetAsync
OnAfterRender
OnAfterRenderAsyncYou do not need to memorize every lifecycle method when starting.
A useful beginner distinction is:
OnInitializedAsync
Useful for initialization work and initial data that doesn't need to reload when component parameters change.
OnParametersSetAsync
Useful when work depends on parameters supplied to the component and may need to run again when those parameters change.
OnAfterRenderAsync
Useful when work must happen after the component has rendered, including some JavaScript interoperability scenarios.
Understanding the lifecycle becomes increasingly important when components start loading data, receiving changing parameters, or interacting with browser APIs.
Creating Forms with EditForm
Blazor provides components for building forms.
A basic product form might look like:
<EditForm Model="product" OnValidSubmit="SaveProduct">
<div>
<label>Product Name</label>
<InputText @bind-Value="product.Name" />
</div>
<div>
<label>Price</label>
<InputNumber @bind-Value="product.Price" />
</div>
<button type="submit">
Save
</button>
</EditForm>
@code {
private Product product = new();
private Task SaveProduct()
{
// Save product
return Task.CompletedTask;
}
}EditForm provides a foundation for handling form state and validation.
Adding Validation
You can use data annotations on your model or dedicated form model.
For example:
public class ProductFormModel
{
[Required]
public string Name { get; set; } = string.Empty;
[Range(0.01, 1000000)]
public decimal Price { get; set; }
}Then configure the form:
<EditForm Model="product" OnValidSubmit="SaveProduct">
<DataAnnotationsValidator />
<ValidationSummary />
<InputText @bind-Value="product.Name" />
<ValidationMessage For="@(() => product.Name)" />
<InputNumber @bind-Value="product.Price" />
<ValidationMessage For="@(() => product.Price)" />
<button type="submit">
Save
</button>
</EditForm>Now invalid values can be shown to the user before the valid submit handler executes.
Validation is particularly important in business applications where incorrect data can affect later calculations and workflows.
Separating UI and Business Logic
One common beginner mistake is putting everything inside .razor components.
For a tiny demo, that may be acceptable.
As an application grows, components should not become responsible for every layer of the system.
Instead of this:
Component
↓
SQL Queryprefer clearer responsibilities:
Blazor Component
↓
Application Service
↓
Repository / Data Access
↓
DatabaseFor example:
public interface IProductService
{
Task<List<Product>> GetProductsAsync();
Task CreateProductAsync(Product product);
}The component can focus on user interaction while the service handles application operations.
This separation makes the application easier to maintain and test.
Using Entity Framework Core with Blazor
Entity Framework Core is commonly used for data access in .NET applications.
A basic DbContext might look like:
public class AppDbContext : DbContext
{
public AppDbContext(
DbContextOptions<AppDbContext> options)
: base(options)
{
}
public DbSet<Product> Products => Set<Product>();
}A service can query products:
public async Task<List<Product>> GetProductsAsync()
{
return await _dbContext.Products
.AsNoTracking()
.ToListAsync();
}The overall flow becomes:
Blazor Component
↓
Product Service
↓
Entity Framework Core
↓
DatabaseDepending on the Blazor hosting and rendering model, the appropriate lifetime and pattern for DbContext usage can differ. Database access should therefore be designed with the application's architecture and execution model in mind rather than placing a long-lived context directly inside UI components.
Blazor and JavaScript Interoperability
Blazor allows C# and JavaScript to work together when necessary.
This is known as JavaScript interoperability, or JS interop.
Inject IJSRuntime:
@inject IJSRuntime JSThen call JavaScript:
await JS.InvokeVoidAsync(
"alert",
"Hello from Blazor");JS interop can be useful for:
Browser APIs
Existing JavaScript libraries
Specialized UI components
Client-side functionality not directly exposed through .NET APIs
Blazor reduces the amount of JavaScript you may need to write, but it does not make JavaScript irrelevant to web development.
Understanding Blazor Rendering Choices
Blazor is not limited to one execution approach.
Modern Blazor applications can use different rendering and interactivity strategies depending on the application's requirements.
At a high level, you may encounter approaches where:
HTML is rendered on the server.
User interactions are handled through a server connection.
Interactive .NET code runs in the browser using WebAssembly.
Different parts of an application use different rendering strategies.
For a beginner, the important lesson is not to memorize every rendering option immediately.
First understand:
Components
Razor syntax
Parameters
Events
Data binding
Routing
Forms
Services
Component lifecycle
Once those fundamentals are clear, learning the different rendering modes becomes much easier because the core component model remains familiar.
Blazor Server-Side Interactivity and WebAssembly: Basic Difference
Two concepts beginners commonly encounter are server-side interactivity and WebAssembly-based interactivity.
With server-side interactivity, much of the .NET application executes on the server while UI events are communicated between the browser and server.
A simplified view is:
Browser
↕
Connection
↕
.NET Application on ServerWith WebAssembly-based interactivity, .NET code can execute in the browser.
A simplified view is:
Browser
↓
WebAssembly
↓
.NET CodeNeither approach is automatically the correct choice for every project.
Factors such as application requirements, network conditions, deployment architecture, offline needs, startup experience, scalability, security boundaries, and where the application logic should execute can influence the decision.
A Practical Blazor Project Structure
A small business application might eventually use a structure such as:
Components
│
├── Layout
├── Shared
├── Products
├── Customers
└── Sales
Models
│
├── Product
├── Customer
└── Sale
Services
│
├── IProductService
├── ProductService
├── ICustomerService
└── CustomerService
Data
│
└── AppDbContextLarger solutions may separate application, domain, infrastructure, and presentation concerns into different projects.
There is no universal folder structure that every Blazor application must follow.
The goal is to keep responsibilities understandable as the system grows.
A Good First Blazor Project
A simple inventory or product management application is a useful first project because it introduces many common business application requirements.
Start with:
Product List
Product Details
Create Product
Edit Product
Delete ProductThen add:
Categories
Search
Filtering
Pagination
Validation
Loading States
Error HandlingAfter that, introduce:
Entity Framework Core
SQL Server or PostgreSQL
Authentication
Authorization
User RolesYou can then expand the same project with:
Customers
Suppliers
Purchases
Sales
Stock
ReportsBuilding one application gradually helps you understand how Blazor concepts work together instead of learning them as disconnected examples.
Common Blazor Mistakes Beginners Should Avoid
Putting Too Much Code in Components
A component should not become your UI, business layer, and data-access layer at the same time.
Move reusable business operations into appropriate services.
Ignoring Component Lifecycle
Loading data in the wrong lifecycle method can create unexpected behavior.
Learn why and when lifecycle methods execute.
Creating Long-Lived Database Contexts Without Considering the Execution Model
DbContext has important lifetime and concurrency considerations.
Choose a data-access pattern appropriate for the type of Blazor application you are building.
Forgetting Loading and Error States
Remote data is not always immediately available.
Your interface should handle loading, empty, success, and failure states.
Building Huge Components
If one component contains hundreds of lines of unrelated UI and logic, consider dividing it into smaller components.
Avoiding JavaScript at All Costs
Blazor allows extensive C# use in the frontend, but JavaScript interoperability exists for a reason.
Use it when browser capabilities or JavaScript libraries make it appropriate.
Learning Only Syntax
Knowing @onclick and @bind is not enough to build maintainable applications.
You should also learn component design, application architecture, validation, security, data access, and state management.
Blazor Learning Path for Beginners
A practical learning path can look like this:
Step 1: Strengthen C# Fundamentals
Learn:
Classes
Interfaces
Collections
Generics
LINQ
Async and await
Step 2: Learn Razor Fundamentals
Understand:
Razor syntax
Components
Directives
C# expressions
Conditional rendering
Step 3: Learn Component Communication
Practice:
Parameters
EventCallback
Parent-child communication
Step 4: Learn Interaction
Practice:
Event handling
Data binding
Component state
Step 5: Learn Routing
Understand:
@pageRoute parameters
NavLinkNavigationManager
Step 6: Learn Forms and Validation
Practice:
EditFormInput components
Data annotations
Validation messages
Step 7: Learn Dependency Injection and Services
Move application operations away from UI components.
Step 8: Learn Data Access
Study:
Entity Framework Core
DbContext
LINQ
Async database operations
Migrations
Step 9: Learn Authentication and Authorization
Protect application features according to user identity and permissions.
Step 10: Build a Complete Application
Combine these concepts into a real project.
Frequently Asked Questions
Is Blazor Good for Beginners?
Blazor can be approachable for developers who already understand C# and basic web development.
A complete beginner to programming should first learn C#, HTML, CSS, and basic web concepts.
Do I Need JavaScript to Learn Blazor?
You can build substantial Blazor functionality using C#, but understanding JavaScript and browser fundamentals remains valuable.
Some browser functionality and third-party libraries may require JavaScript interoperability.
Is Blazor Part of ASP.NET Core?
Blazor is part of the .NET web development ecosystem and integrates closely with ASP.NET Core capabilities.
Can Blazor Use Entity Framework Core?
Yes. Entity Framework Core is commonly used in .NET applications that power Blazor experiences.
The appropriate data-access design depends on how the application is hosted and where its code executes.
Can Blazor Use SQL Server?
Yes. A .NET backend can use Entity Framework Core or another data-access technology to work with SQL Server.
Can Blazor Use PostgreSQL?
Yes. PostgreSQL can also be used with .NET and Entity Framework Core through an appropriate provider.
Can Blazor Build Enterprise Applications?
Blazor can be used for enterprise applications. Architecture, security, scalability, maintainability, testing, infrastructure, and team requirements should still be evaluated for each project.
Is Blazor the Same as Razor Pages?
No.
Both use Razor syntax, but their programming models are different. Blazor focuses on reusable interactive components, while Razor Pages uses a page-focused ASP.NET Core model.
What You Learned
In this tutorial, you learned the foundation of Blazor development:
What Blazor is
How Razor components work
How C# and markup work together
Razor syntax
Event handling
Component parameters
EventCallback
Data binding
Conditional rendering
Routing
Navigation
Dependency injection
Asynchronous data loading
Component lifecycle
Forms
Validation
Service separation
Entity Framework Core integration
JavaScript interoperability
Basic rendering choices
The overall application architecture can eventually look like:
User
↓
Blazor Components
↓
Application Services
↓
Business Logic
↓
Entity Framework Core
↓
SQL Server / PostgreSQLYou do not need to master all of Blazor before starting a project.
Begin with a few components.
Add navigation.
Build a form.
Load data through a service.
Connect a database.
Then gradually introduce validation, authentication, authorization, reusable components, error handling, and more advanced application architecture.
The fastest way to understand Blazor is not to memorize every directive or API.
Build something small, understand why each piece exists, and improve the application one feature at a time.
Final Thoughts
Blazor gives .NET developers a distinctive way to build interactive web applications.
Its biggest advantage is not simply that it lets you write C# instead of JavaScript. The more important benefit is the ability to work within the broader .NET ecosystem while building component-based web interfaces.
A useful mental model is:
Razor Components
↓
C# Application Logic
↓
.NET Services
↓
Entity Framework Core
↓
DatabaseStart with the component model.
Learn parameters, events, binding, routing, and forms.
Then learn how components interact with services and persistent data.
Once those fundamentals are comfortable, move into authentication, authorization, state management, rendering strategies, performance, testing, and deployment.
That progression will take you much further than trying to learn every Blazor feature before building your first application.
Comments 0