Download Sample Code

Event Handling

In today's world, websites are no longer static HTML sites. The evolution of web technology enables users to have numerous interactions with your website. As a crucial part of building an interactive website, handling events allows your website to respond to user interactions, such as clicks, key presses, and other actions. In this tutorial, you will learn:

  • Types of events.
  • Handling HTML events.
  • Creating and handling Blazor events.
  • Canceling ongoing events (preventDefault).
  • Preventing propagation (stopPropagation).

Types of Events

There are 2 types of events: HTML events and Blazor events. HTML events are predefined by the browser and allow developers to respond to user actions, such as clicks or key presses. Blazor events build on top of these HTML events. While HTML events are directly tied to user interactions with elements, Blazor events are linked to the business logic of the application. This separation makes it easier to manage application state, trigger multiple actions, and maintain cleaner, more maintainable code.


Handling HTML Events

An HTML event consists of 2 parts: the name and the arguments. The name indicates how to trigger the event, while the arguments contain information about the event itself. For example, you can detect if the user is holding the Ctrl key when clicking a button by examining the event arguments.

Consider the following example:

<button type="button" onclick="alert(`Is holding Ctrl? ${event.ctrlKey}`)">Handle with JavaScript with event args</button>

In this example, the browser will display a message saying "Is holding Ctrl? true" or "Is holding Ctrl? false" based on the user's action. This event is handled using JavaScript.

In Blazor, you can handle the same HTML event using C#. Here's an example that achieves a similar outcome:

<button type="button" @onclick="HandleHTMLEventWithMouseEvent">
    Handle with C# with event args (Is holding Ctrl? @isHoldingCtrl)
</button>

@code {
    private bool isHoldingCtrl = false;

    private void HandleHTMLEventWithMouseEvent(MouseEventArgs e)
    {
        isHoldingCtrl = e.CtrlKey;
    }
}

To handle an HTML event with C#, you need to declare a method with the corresponding event argument class. In the example above, the C# method HandleHTMLEventWithMouseEvent is declared with MouseEventArgs as its parameter to handle the onclick event. Here's a list of HTML events along with their corresponding C# event argument classes, grouped by event type:

HTML Event C# Event Argument Class
Focus Event
@onfocus FocusEventArgs
@onblur FocusEventArgs
@onfocusin FocusEventArgs
@onfocusout FocusEventArgs
Mouse Event
@onmouseover MouseEventArgs
@onmouseout MouseEventArgs
@onmousemove MouseEventArgs
@onmousedown MouseEventArgs
@onmouseup MouseEventArgs
@onclick MouseEventArgs
@ondblclick MouseEventArgs
@onwheel WheelEventArgs
@onmousewheel WheelEventArgs
@oncontextmenu MouseEventArgs
Drag Event
@ondrag DragEventArgs
@ondragend DragEventArgs
@ondragenter DragEventArgs
@ondragleave DragEventArgs
@ondragover DragEventArgs
@ondragstart DragEventArgs
@ondrop DragEventArgs
Keyboard Event
@onkeydown KeyboardEventArgs
@onkeyup KeyboardEventArgs
@onkeypress KeyboardEventArgs
Input Event
@onchange ChangeEventArgs
@oninput ChangeEventArgs
@oninvalid EventArgs
@onreset EventArgs
@onselect EventArgs
@onselectstart EventArgs
@onselectionchange EventArgs
@onsubmit EventArgs
Clipboard Event
@onbeforecopy EventArgs
@onbeforecut EventArgs
@onbeforepaste EventArgs
@oncopy ClipboardEventArgs
@oncut ClipboardEventArgs
@onpaste ClipboardEventArgs
Touch Event
@ontouchcancel TouchEventArgs
@ontouchend TouchEventArgs
@ontouchmove TouchEventArgs
@ontouchstart TouchEventArgs
@ontouchenter TouchEventArgs
@ontouchleave TouchEventArgs
Pointer Event
@ongotpointercapture PointerEventArgs
@onlostpointercapture PointerEventArgs
@onpointercancel PointerEventArgs
@onpointerdown PointerEventArgs
@onpointerenter PointerEventArgs
@onpointerleave PointerEventArgs
@onpointermove PointerEventArgs
@onpointerout PointerEventArgs
@onpointerover PointerEventArgs
@onpointerup PointerEventArgs
Media Event
@oncanplay EventArgs
@oncanplaythrough EventArgs
@oncuechange EventArgs
@ondurationchange EventArgs
@onemptied EventArgs
@onpause EventArgs
@onplay EventArgs
@onplaying EventArgs
@onratechange EventArgs
@onseeked EventArgs
@onseeking EventArgs
@onstalled EventArgs
@onstop EventArgs
@onsuspend EventArgs
@ontimeupdate EventArgs
@onvolumechange EventArgs
@onwaiting EventArgs
Progress Event
@onloadstart ProgressEventArgs
@ontimeout ProgressEventArgs
@onabort ProgressEventArgs
@onload ProgressEventArgs
@onloadend ProgressEventArgs
@onprogress ProgressEventArgs
@onerror ErrorEventArgs
Other Event
@onactivate EventArgs
@onbeforeactivate EventArgs
@onbeforedeactivate EventArgs
@ondeactivate EventArgs
@onended EventArgs
@onfullscreenchange EventArgs
@onfullscreenerror EventArgs
@onloadeddata EventArgs
@onloadedmetadata EventArgs
@onpointerlockchange EventArgs
@onpointerlockerror EventArgs
@onreadystatechange EventArgs
@onscroll EventArgs
@ontoggle EventArgs

You don’t always need to use event arguments, especially if you don’t care about the event details. Declaring an unused event argument can make your code unnecessarily complex. For example, you might not need to know if the user is holding down a key while clicking a button. Fortunately, you can skip the event argument declaration in such cases. Consider the following example:

<button type="button" onclick="alert('Hello Blazor School!')">Handle with JavaScript</button>

In this example, a message is displayed when the user clicks the button. The event is handled by JavaScript, but you can achieve the same outcome with C# in Blazor:

<button type="button" class="btn btn-primary" @onclick="IncrementCount">
    Handle with C# (@currentCount clicked)
</button>

@code {
    private int currentCount = 0;

    private void IncrementCount()
    {
        currentCount++;
    }
}

Creating and Handling Blazor Events

Just like HTML events, a Blazor event also consists of 2 parts: the name and the argument. However, unlike HTML events, which are predefined by the browser, Blazor events are defined by the developer. Consider the following BlazorDiceRoll.razor component:

<button type="button" @onclick="RollTheDice">Roll Dice!</button>

@code {
    [Parameter]
    public EventCallback<int> OnDiceRolled { get; set; }

    public void RollTheDice() => OnDiceRolled.InvokeAsync(new Random().Next(1, 6));
}

In this example, we created the OnDiceRolled event on top of the HTML onclick event. This Blazor event is used to notify other components when the dice has been rolled. Here’s how the event can be consumed:

<p>Roll the dice. Current dice face: @currentDiceFace</p>
<BlazorDiceRoll OnDiceRolled="UpdateDiceFace" />

@code {
    private int? currentDiceFace;

    private void UpdateDiceFace(int diceFace)
    {
        currentDiceFace = diceFace;
    }
}

In this example, the UpdateDiceFace method is called whenever the OnDiceRolled event is triggered, updating the displayed dice face. This demonstrates how you can create custom Blazor events that communicate between components.

In BlazorDiceRoll.razor, the OnDiceRolled event is defined with the type EventCallback<int>. This means the event is designed to pass a single int parameter when triggered. Consequently, the UpdateDiceFace method must also accept a single int parameter.

If you try to add more parameters to the UpdateDiceFace method, the project will fail to build. This is because the event and its handler must have matching parameter types and counts for Blazor to correctly bind them together.

Similar to HTML events, Blazor events don’t always require event arguments, which can help simplify your code when they aren't needed. Consider the following BlazorRating.razor component:

<div>
    <label><input type="radio" name="rating" @onchange="On5StarsSelected" />*****</label>
    <label><input type="radio" name="rating" />****</label>
    <label><input type="radio" name="rating" />***</label>
    <label><input type="radio" name="rating" />**</label>
    <label><input type="radio" name="rating" />*</label>
</div>

@code {
    [Parameter]
    public EventCallback On5StarsSelected { get; set; }
}

In this example, the On5StarsSelected event is declared without any event argument. Here's how it can be consumed:

<p>How much do you love Blazor? Select 5 stars to increase this number: @selected5StarsCount</p>
<BlazorRating On5StarsSelected="IncrementCount" />

@code {
    private int selected5StarsCount = 0;

    private void IncrementCount()
    {
        selected5StarsCount++;
    }
}

Each time a user selects 5 stars, the count is incremented by 1. Notice that the IncrementCount method, which handles the On5StarsSelected event, has no parameters.

If you try to add parameters to the IncrementCount method, the project will fail to build. This is because the method signature must exactly match the event's definition, which in this case, has no arguments.


Canceling Ongoing Events (preventDefault)

Every HTML event comes with default behaviors, and developers can block these using preventDefault. For instance, with a checkbox input, clicking it normally causes the browser to tick it—this is its default behavior. Here’s an example that prevents the checkbox from being ticked when the user clicks it.
<label>
    <input type="checkbox" @onclick="_ => showMessage = true" @onclick:preventDefault />
    @if (showMessage)
    {
        <span>The checkbox can’t be checked because the <code>onclick</code> event was cancelled using <code>@onclick:preventDefault</code>.</span>
    }
    else
    {
        <span>Click the checkbox</span>
    }
</label>

@code {
    private bool showMessage = false;
}

Preventing Propagation (stopPropagation)

HTML elements can be nested at multiple levels, like boxes inside boxes. When you click an element, an event starts at that spot and travels up through its parent elements—this is called event bubbling. In Blazor, you can stop this bubbling with stopPropagation. Take a look at this example:

<button type="button" @onclick='_ => Message += "<code>Level 1</code> clicked. "'>
    Level 1
    <button type="button" @onclick='_ => Message += "<code>Level 2</code> clicked. "'>
        Level 2
        <button type="button" @onclick='_ => Message += "<code>Level 3</code> clicked. "'>
            Level 3
        </button>
    </button>
</button>

In this example, we have 3 nested buttons, with the Level 1 button as the outermost and Level 3 as the innermost. Imagine the user clicks on Level 3: the onclick event will propagate from Level 3 to Level 2, and then from Level 2 to Level 1. All 3 buttons register as clicked.

Now, let's add @onclick:stopPropagation to the Level 2 button. With this change, the propagation goes only from Level 3 to Level 2 and stops there.

BLAZOR SCHOOL
Designed and built with care by our dedicated team, with contributions from a supportive community. We strive to provide the best learning experience for our users.
Docs licensed CC-BY-SA-4.0
Copyright © 2021-2025 Blazor School
An unhandled error has occurred. Reload 🗙