Layouts in Blazor

Certain layout elements like menus, copyright messages, logos, etc. must be present on all pages. Copying the code of these layout elements onto all pages would not be a good solution. The app would become hard to maintain and probably inconsistent over time. Blazor Layouts solve this problem. Layout page helps us to reduce duplicate code in our application and helps us to make the look and feel consistent throughout the application. It is very similar to Layout in ASP.net MVC application. Blazor also supports nested layout.

Lets add bootstrap components in our layout

We will add bootstrap to our project by adding the bootstrap CDN betwen the header tags in the index.html in the /wwwroot folder. Blazor use a modified version of bootstrap, by adding the official bootstrap CDN we will  be able to use the official bootstrap documentation.

Remember to comment out Blazor default bootstrap css!

/wwwroot/index.html
 <!--
    <link href="css/bootstrap/bootstrap.min.css" rel="stylesheet" />
    <link href="css/site.css" rel="stylesheet" />
    -->

    <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/css/bootstrap.min.css" integrity="sha384-Gn5384xqQ1aoWXA+058RXPxPg6fy4IWvTNh0E263XmFcJlSAwiGgFAW/dAiS6JXm" crossorigin="anonymous">
    <link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.2.0/css/all.css" integrity="sha384-hWVjflwFxL6sNzntih27bfxkr27PmbbK/iSvJ+a4+0owXq79v+lsFkW54bOGbiDQ" crossorigin="anonymous">

What makes a Layout?

Layouts are technically another Blazor component. A layout is defined in a Razor template or in C# code and can contain data binding, dependency injection, and other ordinary features of components. Two additional aspects turn a component into a layout:

  1. The layout component must inherit from BlazorLayoutComponent. BlazorLayoutComponent defines a Body property that contains the content to be rendered inside the layout.
  2. The layout component uses the Body property to specify where the body content should be rendered using the Razor syntax @Body. During rendering, @Body is replaced by the content of the layout.

Create a Razor View file in the ‘Shared’ folder, we will name the file AppLayout.cshtml. The following code sample shows the Razor template of a layout component. Note the use of BlazorLayoutComponent and @Body:

AppLayout.cshtml
@inherits BlazorLayoutComponent

<div class="">
    <NavBarMenu />
</div>

<div class="main">
    
    <div class="content px-4" style="padding-top:65px">
        @Body
    </div>
</div>

The <NavBarMenu> tags are a custom navbar component in the ‘shared’ folder

/shared/NavBarMenu.cshtml
<nav class="navbar navbar-expand-lg navbar-dark bg-dark">
    <a class="navbar-brand" href="#">Navbar</a>
    <button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarSupportedContent" aria-controls="navbarSupportedContent" aria-expanded="false" aria-label="Toggle navigation">
        <span class="navbar-toggler-icon"></span>
    </button>

    <div class="collapse navbar-collapse" id="navbarSupportedContent">
        <ul class="navbar-nav mr-auto">
            <li class="nav-item active">
                <a class="nav-link" href="/">Home</a>
            </li>
            <li class="nav-item">
                <a class="nav-link" href="counter">Counter</a>
            </li>
            
            <li class="nav-item">
                <a class="nav-link " href="fetchdata">Fetch Data</a>
            </li>
        </ul>
        
    </div>
</nav>
There two ways to render component with Layouts:
  1. Using @layout directive or Layout attribute
  2. Define layout globally
Using ‘@layout’ directive or Layout Attribute
We can define the layout for Blazor component by using @layout directive. At the time of compilation, @layout directive converted into Layout attribute which applied to the Blazor component class. Either way, if our component is class based, we can use Layout attribute directly in class.
Using '@Layout' directive:
@layout MainLayout  
@page "/layoutdirective"  
  
<h2>@Title</h2>  
  
@functions {  
    string Title = "The layout of this page has been set using @Layout directive.";  
}  
    using BlazorDemoApp.Shared;  
    using Microsoft.AspNetCore.Blazor.Components;  
    using Microsoft.AspNetCore.Blazor.Layouts;  
    using Microsoft.AspNetCore.Blazor.RenderTree;  
      
    namespace BlazorDemoApp.Pages  
    {  
        [Route("/usingattribute")]  
        [Layout(typeof(MainLayout))]  
        public class LayoutDefinedUsingAttribute : BlazorComponent  
        {  
            public string Title { get; set; } = "The Layout of the page was defined using layout Attribute";  
            protected override void BuildRenderTree(RenderTreeBuilder builder)  
            {  
                builder.OpenElement(1, "h1");  
                builder.AddContent(2, Title);  
                builder.CloseElement();  
            }  
        }  
    }  

Global Layout

The ‘_ViewImports.cshtml’ file was introduced in ASP.net MVC and it provides a mechanism to make directives available to Razor pages globally so that we aren’t required to add them to pages individually. We can also use this file to define Layout page in Blazor. If we define Layout page in this file, Layout is automatically applied to all the Blazor pages in the folder heirarchy.

_ViewImports.cshtml
@layout AppLayout 

Note:

We can also define the namespaces that are used in all the views in a folder to _viewImports.cshtml file.

Let’s run the project

We now have created a layout to render our application components and got bootstrap running inside. We have created a base for our application to start from scratch.

Here is a gif of the project running

Nested layouts

Blazor component also supports the nested layouts; i.e., Blazor component can reference a layout which references another layout.
MainLayout.cshtml
    @implements ILayoutComponent  
      
    <div class="container-fluid">  
        <div class="row">  
            <div class="col-sm-3">  
                <NavMenu />  
            </div>  
            <div class="col-sm-9">  
                @Body  
            </div>  
        </div>  
    </div>  
      
    @functions {  
        public RenderFragment Body { get; set; }  
    }  
OtherLayout.cshtml
    @layout MainLayout  
    @implements ILayoutComponent  
      
    <div class="container-fluid">  
        <div class="row">  
            <div class="col-sm-12">  
                <h2>Nested Layout Example</h2>  
            </div>  
        </div>  
        <div class="row">  
            <div class="col-sm-12">  
                @Body  
            </div>  
        </div>  
    </div>  
      
    @functions {  
        public RenderFragment Body { get; set; }  
    }  
nestestedLayout.cshtml
    @layout OtherLayout  
    @page "/nestedlayout"  
      
    <h3>@Title</h3>  
      
    @functions {  
        string Title = "This is child page";  
    }  

Take Away

Now that you know how to create and use layouts, you can take advantage of this and design faster and better-looking web applications.