Layout Pages
Every page of a site shares a header, a menu and a footer. A layout page holds that shell once, so each view only contains what is different.
On this page · 6 min · Intermediate
On this page
- Learning objectives
- Explanation
- Syntax
- Code example
- Step by step
- Real-world use
- Common mistakes
- Best practices
- Remember this
- Practice exercise
- Mini quiz
- Related topics
- My notes
- Reading time
- 6 min
- Difficulty
- Intermediate
- Updated
- Oct 29, 2026
Related tutorials
Learning objectives#
- Build a layout with RenderBody
- Define optional and required sections
- Set the default layout in _ViewStart
- Pass a page title from views to the layout
Explanation#
A layout is a view (by convention Views/Shared/_Layout.cshtml) with the full HTML page. It calls @RenderBody() exactly once, where the current view’s output goes.
Views/_ViewStart.cshtml runs before every view and sets Layout = "~/Views/Shared/_Layout.cshtml", so views use it automatically. A view can set a different Layout or Layout = null.
Sections let a view put content in other places of the layout: the view writes @section scripts { ... } and the layout calls @RenderSection("scripts", required: false). If a section is required and missing, rendering fails.
The view runs before the layout, so values set in the view (ViewBag.Title) are available in the layout’s <title>.
IsSectionDefined("sidebar") lets the layout show default content when a view does not provide a section.
Syntax#
@* _Layout.cshtml *@
<title>@ViewBag.Title</title>
<main>@RenderBody()</main>
@RenderSection("scripts", required: false)
@* A view *@
@{ ViewBag.Title = "Cart"; }
<h1>Your cart</h1>
@section scripts { <script src="~/Scripts/cart.js"></script> }
Code example: A layout with a title, a body and two sections#
// Controllers/PagesController.cs
using System.Web.Mvc;
namespace ShopSite.Controllers
{
public class PagesController : Controller
{
public ActionResult Cart() => View();
public ActionResult Terms() => View();
}
}
@* Views/_ViewStart.cshtml *@
@{
Layout = "~/Views/Shared/_Layout.cshtml";
}
@* Views/Shared/_Layout.cshtml *@
<!DOCTYPE html>
<html>
<head>
<title>@ViewBag.Title | Shop</title>
</head>
<body>
<header><a href="/">Shop</a></header>
<aside>
@if (IsSectionDefined("sidebar"))
{
@RenderSection("sidebar")
}
else
{
<p>Free delivery over 500 rupees</p>
}
</aside>
<main>
@RenderBody()
</main>
<footer>© 2026 Shop</footer>
@RenderSection("scripts", required: false)
</body>
</html>
@* Views/Pages/Cart.cshtml *@
@{ ViewBag.Title = "Your cart"; }
<h1>Your cart</h1>
<p>2 items</p>
@section sidebar {
<p>Have a coupon? Apply it at checkout.</p>
}
@section scripts {
<script src="/Scripts/cart.js"></script>
}
@* Views/Pages/Terms.cshtml *@
@{ ViewBag.Title = "Terms"; }
<h1>Terms of sale</h1>
GET /Pages/Cart
200 OK
<!DOCTYPE html>
<html>
<head>
<title>Your cart | Shop</title>
</head>
<body>
<header><a href="/">Shop</a></header>
<aside>
<p>Have a coupon? Apply it at checkout.</p>
</aside>
<main>
<h1>Your cart</h1>
<p>2 items</p>
</main>
<footer>© 2026 Shop</footer>
<script src="/Scripts/cart.js"></script>
</body>
</html>
GET /Pages/Terms
200 OK
<!DOCTYPE html>
<html>
<head>
<title>Terms | Shop</title>
</head>
<body>
<header><a href="/">Shop</a></header>
<aside>
<p>Free delivery over 500 rupees</p>
</aside>
<main>
<h1>Terms of sale</h1>
</main>
<footer>© 2026 Shop</footer>
</body>
</html>This example is illustrative. Copy or download it and run it in your own environment; the expected output is shown above.
Step-by-step explanation#
- _ViewStart sets the layout for every view in the Views folder.
- Cart.cshtml runs first: it sets ViewBag.Title, produces its body HTML and defines two sections.
- The layout then runs. The title uses the value set by the view, RenderBody inserts the body, and the sections appear where RenderSection is called.
- Terms defines no sections, so the layout shows the default sidebar text and the optional scripts section renders nothing.
Real-world use case#
A company rebrands its intranet. Because every one of its 140 pages uses the same _Layout.cshtml, the new header, colours and footer go live by changing one file.
Common mistakes#
A layout must call RenderBody exactly once, otherwise MVC throws “The RenderBody method has not been called”.
@RenderSection("scripts") without required: false makes every view without that section fail. Make optional sections optional.
The layout runs after the view, so a title set in the layout overwrites the view’s title. Set it in the view.
Best practices#
- One main layout plus specialised layouts (admin, print) that can nest
- Put scripts in a scripts section at the end of the body
- Use IsSectionDefined for sensible defaults
- Keep layouts free of business logic; use child actions or partials for menus
Remember this#
Layout = shell; RenderBody = this page.
_ViewStart sets the default layout.
View runs first, layout second.
Practice exercise#
Your task: Create a _PrintLayout.cshtml with no header or footer and make an Invoice view use it by setting Layout in the view.
Need a hint?
Show solution
// Controllers/PrintController.cs
using System.Web.Mvc;
namespace ShopSite.Controllers
{
public class PrintController : Controller
{
public ActionResult Invoice() => View();
}
}
@* Views/Shared/_PrintLayout.cshtml *@
<!DOCTYPE html>
<html>
<head><title>Print</title></head>
<body class="print">
@RenderBody()
</body>
</html>
@* Views/Print/Invoice.cshtml *@
@{ Layout = "~/Views/Shared/_PrintLayout.cshtml"; }
<h1>Invoice #1001</h1>
GET /Print/Invoice 200 OK <!DOCTYPE html> <html> <head><title>Print</title></head> <body class="print"> <h1>Invoice #1001</h1> </body> </html>
Mini quiz#
Which call inserts the current view into a layout?
Want more? Practise all ASP.NET MVC MCQs · ASP.NET MVC interview questions
My notes#
Saved in this browser.