Creating a Reusable, JavaScript-Free Blazor Modal
Tags: dotnet, blazor, razor
Published: 2019-01-29 14:09:25

---
title: Creating a Reusable, JavaScript-Free Blazor Modal
published: true
tags: dotnet, blazor, razor
canonical_url: https://www.telerik.com/blogs/creating-a-reusable-javascript-free-blazor-modal
---

In this guide, Chris Sainty helps you learn how to build a reusable modal without using any JavaScript for your Blazor and Razor applications.

Modals are a common feature of today’s web applications. You will find them in most UI frameworks, and they range from simple confirmation boxes to full-blown forms. In this post, I’m going to walk you through building a JavaScript-free, reusable modal for your Blazor/Razor Components applications. To make things even more interesting, we’re going to build the modal in such a way that we can pass it components to display instead of just plain text or markup strings.

For anyone new to Blazor, let me give you a quick overview. Blazor is a SPA-like framework developed by Microsoft. There is a client-side model, which runs via a [WebAssembly-based .NET runtime](https://dev.to/progresstelerik/goodbye-javascript-hello-webassembly-6oc-temp-slug-9525238). There’s also a server-side model (Razor Components), which runs on the standard .NET Core runtime. You can find out more at [Blazor.net](https://blazor.net).

## Getting Set Up

If you’re new to Blazor development, then you will need to make sure you have the latest version of the [.NET Core SDK installed](https://dotnet.microsoft.com/download). You will also need to install the [Blazor Language services](https://marketplace.visualstudio.com/items?itemName=aspnet.blazor), as well as the Blazor templates via the dotnet CLI.

```
dotnet new -i Microsoft.AspNetCore.Blazor.Templates

```

### Creating a Blazor Library

We want to be able to use our modal in whatever projects we see fit. The best way to achieve this is by using the Blazor Library project included in the CLI templates we installed above. This project type works in a similar way to a class library and allows us to share components and their assets (images, CSS, etc.) between Blazor applications.

As this project type is currently only available using the dotnet CLI, we can run the following commands to create a new directory as well as the Blazor Library project.

```
mkdir BlazorModal
cd BlazorModal
dotnet new blazorlib

```

Now we have a new Blazor library project we can open in Visual Studio. Before we do anything else, let’s remove some of the default items that come with the template. The only thing we want to keep is the styles.css, so the project should look like this.

![EmptyBlazorLibrary](https://d585tldpucybw.cloudfront.net/sfimages/default-source/blogs/2019/january/emptyblazorlibrary.png?sfvrsn=82dbf50_1 "EmptyBlazorLibrary")

## Modal Service

The first thing we are going to build is the `ModalService`. This is going to be the glue which will join our modal component with any other components that wish to use it. In the root of the project, add a new class called _ModalService.cs_ with the following code.

```
using Microsoft.AspNetCore.Blazor;
using Microsoft.AspNetCore.Blazor.Components;
using System;

namespace BlazorModal.Services
{
public class ModalService
{
public event Action<string, RenderFragment> OnShow;
public event Action OnClose; 

public void Show(string title, Type contentType)
{
if (contentType.BaseType != typeof(BlazorComponent))
{
throw new ArgumentException($"{contentType.FullName} must be a Blazor Component");
}

var content = new RenderFragment(x => { x.OpenComponent(1, contentType); x.CloseComponent(); });
OnShow?.Invoke(title, content);
}

public void Close()
{
OnClose?.Invoke();
}
}
}

```

So what’s going on here?

The class exposes two methods, `Show()` and `Close()`, as well as a couple of events. The Show method is the interesting one, though. After checking that the type passed in via the `contentType` argument is a Blazor component, it creates a new `RenderFragment` using said type. This is then passed into the `OnShow` event so it can be used by an event handler. We’ll get to that in a bit.

Now before we go any further, I know what some of you are thinking… _What’s a RenderFragment??_

In simple terms, a `RenderFragment` represents a piece of UI. Blazor uses these `RenderFragments` to output the final HTML in the browser. In the code above, if we passed in a type of `Foo`, the resulting HTML would look like this.

```
<Foo></Foo>

```

There are many interesting uses for `RenderFragment` especially when dealing with dynamic component generation, but that is a topic for another time. Let’s crack on.

### IServiceCollection Extension

When creating a library, I always find it a good idea to provide an extension method which can handle registering services with the DI container. It makes sure that everything gets registered with the correct scope, plus consumers only have to add a single line to their apps. Add a new class to the root of the project called _ServiceCollectionExtension.cs_ with the following code.

```
using BlazorModal.Services;
using Microsoft.Extensions.DependencyInjection;

namespace BlazorModal
{
public static class ServiceCollectionExtensions
{
public static IServiceCollection AddBlazorModal(this IServiceCollection services)
{
return services.AddScoped<ModalService>();
}
}
}

```

## Modal Component

Now that the service is in place, we can build the modal component. I always like to separate the logic and the markup of my components. This is achieved by creating a base class with all the logic that the component will inherit, leaving the component with just markup.

First add a new **Razor View** named _Modal.cshtml_, then add a new class called _Modal.cshtml.cs_. The reason for this naming is so that Visual Studio will nest the base class under the Razor View. You don’t have to follow this convention, but it does keep the solution window nice and tidy. Also be sure it’s a Razor View you select and not a Razor Page — Razor Pages won’t work.

Let’s look at the base class logic first.

Oh! One other thing. You will need to change the name of the base class. As you can see in the code below, I’ve stuck _Base_ on the end. Again, you can call it what you want. Model is another popular choice. But this is to stop a name clash with the code generated by _Modal.cshtml_.

### Component Logic

```
using BlazorModal.Services;
using Microsoft.AspNetCore.Blazor;
using Microsoft.AspNetCore.Blazor.Components;
using System;
 
namespace BlazorModal
{
public class ModalBase : BlazorComponent, IDisposable
{
[Inject] ModalService ModalService { get; set; }

protected bool IsVisible { get; set; }
protected string Title { get; set; }
protected RenderFragment Content { get; set; }
  
protected override void OnInit()
{
ModalService.OnShow += ShowModal;
ModalService.OnClose += CloseModal;
}
  
public void ShowModal(string title, RenderFragment content)
{
Title = title;
Content = content;
IsVisible = true;

StateHasChanged();
}

public void CloseModal()
{
IsVisible = false;
Title = "";
Content = null;

StateHasChanged();
}

public void Dispose()
{
ModalService.OnShow -= ShowModal;
ModalService.OnClose -= CloseModal;
}
}
}

```

Working from the top, we inject an instance of the modal service. Then we’re declaring a few parameters that we’ll be using in the markup side of the component. We’re overriding one of Blazor’s lifecycle methods, `OnInit`, so we can attach the `ShowModal` and `CloseModal` methods to the respective `OnShow` and `OnClose` events from the modal service.

The `ShowModal` and `CloseModal` methods are pretty self-explanatory. The only part that is probably worth pointing out is the call to `StateHasChanged`. We need to call `StateHasChanged` due to the fact that these methods are invoked from outside of the component. And all this method does is tell the component that something has changed so it needs to re-render itself.

Finally, the component implements the `IDisposable` interface so we can unregister the event handlers when the component is destroyed.

Now let’s look at the markup side.

### Component Markup

```
@inherits ModalBase

<div class="bm-container @(IsVisible ? "bm-active" : string.Empty)">

    <div class="bm-overlay" onclick="@CloseModal"></div>

    <div class="blazor-modal">
        <div class="bm-header">
            <h3 class="bm-title">@Title</h3>
            <button type="button" class="bm-close" onclick="@CloseModal">
                <span>&times;</span>
            </button>
        </div>
        <div class="bm-content">
            @Content
        </div>
    </div>

</div>

```

The first line is a directive stating the component is inheriting from `ModalBase`. Next we have a container div with a bit of Razor syntax which uses the `IsVisible` property to toggle the `bm-active` class. This is what’s responsible for showing or hiding the component.

The next div is for creating a darkened overlay that the modal will sit on. This also has a `onclick` handler which closes the modal if a user clicks anywhere on the overlay.

Then we come to the modal itself. It has a header which displays the title along with a button that can be used to close the modal. The `@Content` marker is where the `RenderFragment` we talked about earlier will be displayed.

## Adding a Bit of Style

No component would be complete without a bit of styling. There is nothing special or clever her — I’m by no means a CSS guru. But the following classes should give everything a nice clean look and feel with the modal being centered both horizontally and vertically on the page. All thanks to the wonders of Flexbox!

```
.bm-container {
    display: none;
    align-items: center;
    justify-content: center;
    position: fixed;
    width: 100%;
    height: 100%;
    z-index: 2;
}

.bm-overlay {
    display: block;
    position: fixed;
    width: 100%;
    height: 100%;
    z-index: 3;
    background-color: rgba(0,0,0,0.5);
}

.bm-active {
    display: flex;
}

.blazor-modal {
    display: flex;
    flex-direction: column;
    width: 50rem;
    background-color: #fff;
    border-radius: 4px;
    border: 1px solid #fff;
    padding: 1.5rem;
    z-index: 4;
}

.bm-header {
    display: flex;
    align-items: flex-start;
    justify-content: space-between;
    padding: 0 0 2rem 0;
}

.bm-title {
    margin-bottom: 0;
}

.bm-close {
    padding: 1rem;
    margin: -1rem -1rem -1rem auto;
    background-color: transparent;
    border: 0;
    -webkit-appearance: none;
    cursor: pointer;
}

```

## Testing it Out

We have now built our modal, but it would be good to see it all in action. Let’s add a standalone Blazor app to the solution so we can try it out. This will work just as well with a server-side project if you prefer.

Right-click on the solution and Add > New Project. Then select ASP.NET Core Web Application and give it a name. I’m going to call it BlazorTest. Finally, select Blazor as the project type from the dialogue.

If you prefer, you could use the CLI with the following command.

```
dotnet new blazor -n BlazorTest

```

We also need to add a project reference from the BlazorTest (or whatever you’ve called it) to the BlazorModal project. Your solution should now look like this.

![SolutionWithTestProject](https://d585tldpucybw.cloudfront.net/sfimages/default-source/blogs/2019/january/solutionwithtestproject.png?sfvrsn=1ed29280_1 "SolutionWithTestProject")

### Setting Up the Test Project

Now that we have a test project, we need to do three things to register our modal for use.

First, we need to add the following lines into the _\_ViewImports.cshtml_.

```
@using BlazorModal
@using BlazorModal.Services

@addTagHelper *, BlazorModal

```

The using statements will save us having to use fully qualified names when using the `ModalService`. The `addTagHelper` will import all components from the specified namespace.

Second, we need to add our `ModalService` to the DI container. Due to our earlier work creating the service collection extension method, we just need to add the following to the `ConfigureServices` method in _Startup.cs_.

```
using BlazorModal;

// Other code omitted for brevity

public void ConfigureServices(IServiceCollection services)
{
services.AddBlazorModal();
}

```

The third and final task is to add the modal component to the _MainLayout.cshtml_.

```
@inherits BlazorLayoutComponent

<Modal />

<div class="sidebar">
<NavMenu />
</div>

<!—Remaining code omitted for brevity -->

```

We have now setup the test project to use our modal component.

### Creating a Test Component

In order to test our modal we are going to create a simple form component that we will display in our modal. In the _Pages_ folder, add a new Razor View called _SimpleForm.cshtml_ and add the following code.

```
@if (ShowForm)
{
<div class="simple-form">
<div class="form-group">
<label for="first-name">First Name</label>
<input bind="@FirstName" type="text" class="form-control" id="first-name" placeholder="Enter email" />
</div>
<div class="form-group">
<label for="last-name">Last Name</label>
<input bind="@LastName" type="text" class="form-control" id="last-name" placeholder="Enter email" />
</div>
<button onclick="@SubmitForm" class="btn btn-primary">Submit</button>
</div>
}
else
{
<div class="alert alert-success" role="alert">
Thanks @FirstName @LastName for submitting the form.
</div>
}

@functions {
bool ShowForm { get; set; } = true;
string FirstName { get; set; }
string LastName { get; set; }

void SubmitForm()
{
ShowForm = false;
}
}

```

The component takes the user’s first and last names and then shows them a personalized message after they click submit.

All that’s left is to call it. Let’s make some additions to the _Index_ component to call our modal with the simple form we’ve just created.

```
@page "/"
@inject ModalService ModalService

<h1>Hello, world!</h1>
Welcome to your new app.

<SurveyPrompt Title="How is Blazor working for you?" />

<hr />

<button onclick="@ShowModal">Show Modal</button>

@functions {
private void ShowModal()
{
ModalService.Show("Simple Form", typeof(SimpleForm));
}
}

```

And we’re done! This is what the finished _Index_ component looks like.

### Running Our Test App

We can now run our test app and if all has gone to plan it should work something like this.

![BlazorModal](https://d585tldpucybw.cloudfront.net/sfimages/default-source/blogs/2019/january/blazormodal.gif?sfvrsn=6aa58b90_1 "BlazorModal")

## Wrapping Up

In this post, we’ve built a reusable modal without using any JavaScript. We’ve also built it in such a way that we can display other components which I think is a really nice feature and fits nicely with Blazor’s component model.

All the code for this post is available on my [GitHub](https://github.com/chrissainty/BlazorModal).

### Related News

Looking for more news and info on Blazor? Check out these recommended resources:

- [Blazor – A New Framework for Browser-based .NET Apps (DevReach 2018)](https://www.youtube.com/watch?v=BnH2h_RJ-d8&t=0s&list=PLvmaC-XMqeBYiMKlRATiIuxKF5Czb_aW7&index=8)
- [What’s Coming in .NET Core 3.0](https://msdn.microsoft.com/en-us/magazine/mt848631.aspx)
- [Blazor Q&A with Microsoft’s Daniel Roth](https://dev.to/progresstelerik/blazor-qa-with-microsofts-daniel-roth-3d48)
- [Goodbye JavaScript, Hello WebAssembly](https://dev.to/progresstelerik/goodbye-javascript-hello-webassembly-6oc-temp-slug-9525238)
- [A Breakdown of Blazor Project Types](https://dev.to/progresstelerik/a-breakdown-of-blazor-project-types-2b4g-temp-slug-848040)
- [Razor Components for a JavaScript-Free Front-end in 2019](https://dev.to/progresstelerik/razor-components-for-a-javascript-free-frontend-in-2019-1f6o)
- [Introducing the Telerik UI for Blazor Early Preview](https://dev.to/progresstelerik/introducing-the-telerik-ui-for-blazor-early-preview-2f4c)