How To Create a Mega Menu in Umbraco 7

When we create very basic websites, the primary menu will very likely be made up from the child pages under the homepage.  When we want to create more advanced menus, then this limitation of needing a page to live in a certain area is very annoying.

On most projects I build nowadays, I usually end up creating a variation of a mega menu, using a standard CMS based pattern for creating advanced menus.  In today’s guide, I’m going to cover how to create such a menu.  I’ll also be using uSiteBuilder as part of this guide.  If you want to know how to use uSitebuilder I have written this guide, How To Build An Umbraco 7 Document Types In Visual Studio – USiteBuilder Explained . To fully understand the project available from my GitHub that accompanies this article, I would also recommend reading How To Create A Global View Model For Umbraco With uSitebuilder.

The mega-menu we are going to create will look like this:

umbraco_mega_menu

The Menu Container

This first thing we will need is a container page that we can use as a placeholder to create a menu.  This container page will not be displayed on our website, it will live on the same hierarchy level as the homepage in our CMS content tree. The code to create this document type will look like this:

[DocumentType(Name = "Mega Menu Container",
Description = "This is the container for the meag menu.")]
public class MenuContainerDocumentType : Vega.USiteBuilder.DocumentTypeBase
{
}   

The code is simple, all we really need is a container, that doesn’t need any properties. In Umbraco CMS create a Menu container:

umbraco_creating_menu_container

The Menu Document Type

Now, in some projects you could get away with not following this step, although I do not recommend it.  Now we have a container area for the menu, we could create a ‘Menu Item’ document type, add them under the container and just that as the basis of the new menu.

The problem with this approach, is that what happens if you need to create more than one menu (like a secondary menu), you need to implement a multi-language project at a later date and you need different menus for each language or, another common one, you want to do A/B testing on your menu to see what converts the best.  If any of these sound like potential requirements, then it’s a good idea to be able to create multiple menus. We do that by creating a Menu Document Type. Like the menu container, the menu document type is a simple places holder.

The code for the menu container looks like this,

[DocumentType(Name = "Mega Document Type",
Description = "Creates a new menu.")]
public class MenuDocumentType : Vega.USiteBuilder.DocumentTypeBase
{
[DocumentTypeProperty(UmbracoPropertyType.Textstring, 
Name = "Menu Name", 
Tab = "Menu", 
Description = "Menu Name")]
public string MenuName { get; set; }
}   

We also need to update the menu container now, to allow MenuDocument types to be created as children:

[DocumentType(Name = “Mega Menu Container”,
Description = “This is the container for the meag menu.”,
AllowedChildNodeTypes = new Type[] { typeof(MenuDocumentType) } )]
public class MenuContainerDocumentType : Vega.USiteBuilder.DocumentTypeBase
{
}
[/csahrp]

Go back to the Umbraco back-end and we can now create a menu page, under the menu container:

umbraco_creating_menu_type

then create the page

umbraco_creating_menu_type_second_step

Menu Item Document Type

Now we start to get to the interesting parts. The next step is to create the menu items. These will be the top level items that will get displayed in our menus.

[DocumentType(Name = "Mega Item Document Type",
Description = "Creates a new top level menu item.",
AllowedChildNodeTypes = new Type[] { typeof(SubMenuItemDocumentType) })]
public class MenuItemDocumentType : Vega.USiteBuilder.DocumentTypeBase
{
[DocumentTypeProperty(UmbracoPropertyType.Textstring, 
Name = "Menu Title",
Description = "Menu Title",
Tab = "Menu")]
public string MenuTitle { get; set; }
[DocumentTypeProperty(UmbracoPropertyType.ContentPicker,
Name = "Menu Link",
Description = "Menu Link",
Tab = "Menu")]
public string MenuLink { get; set; }

The menu document type is the top level, items that will be displayed in our website. The first property ‘MenuTitle’ is the text that will be displayed for the menu item, next we have the Url the menu will point to and lastly, we have an image property to set the image for the menu item.

Now we have another child template, we need to set the ‘Menu Document Type’ to allow ‘Menu Items’ to be created as child nodes:

[DocumentType(Name = "Mega Document Type",
Description = "Creates a new menu.",
AllowedChildNodeTypes = new Type[] { typeof(MenuItemDocumentType) })]
public class MenuDocumentType : Vega.USiteBuilder.DocumentTypeBase

Menu Link

Now we have everything to create a menu, we need a way to set it.  To do this I usually add a property to the home page document type, called menu:

[DocumentTypeProperty(UmbracoPropertyType.ContentPicker,
Name = "Menu Link",
Tab = "Menu Setting",
Description = "Menu Link")]
public string MenuLink { get; set; }

In order for a menu to be used, a content editor needs to go into the back-end, and, on the homepage, pick the menu they want to use, save and publish it.

Sub Menu Document Type

The last document type we need to create is the sub menu item, these are the sub links that will be displayed under our main navigation.

[DocumentType(Name = "Sub Menu Item Document Type",
Description = "Creates a new sub level menu item that sits under a menu item.")]
public class SubMenuItemDocumentType : Vega.USiteBuilder.DocumentTypeBase
{
[DocumentTypeProperty(UmbracoPropertyType.Textstring,
Name = "Menu Title",
Description = "Menu Title",
Tab = "Menu")]
public string MenuTitle { get; set; }
[DocumentTypeProperty(UmbracoPropertyType.ContentPicker,
Name = "Menu One Link",
Description = "Menu One Link",
Tab = "Menu")]
public string MenuOneLink { get; set; }
[DocumentTypeProperty(UmbracoPropertyType.Textstring,
Name = "Menu One Title",
Description = "Menu One Title",
Tab = "Menu")]
public string MenuOneTitle { get; set; }
[DocumentTypeProperty(UmbracoPropertyType.ContentPicker,
Name = "Menu Two Link",
Description = "Menu Two Link",
Tab = "Menu")]
public string MenuTwoLink { get; set; }
[DocumentTypeProperty(UmbracoPropertyType.Textstring,
Name = "Menu Two Title",
Description = "Menu Two Title",
Tab = "Menu")]
public string MenuTwoTitle { get; set; }
[DocumentTypeProperty(UmbracoPropertyType.ContentPicker,
Name = "Menu Three Link",
Description = "Menu Three Link",
Tab = "Menu")]
public string MenuThreeLink { get; set; }
[DocumentTypeProperty(UmbracoPropertyType.Textstring,
Name = "Menu Three Title",
Description = "Menu Three Title",
Tab = "Menu")]
public string MenuThreeTitle { get; set; }
[DocumentTypeProperty(UmbracoPropertyType.ContentPicker,
Name = "Menu Four Link",
Description = "Menu Four Link",
Tab = "Menu")]
public string MenuFourLink { get; set; }
[DocumentTypeProperty(UmbracoPropertyType.Textstring,
Name = "Menu Four Title",
Description = "Menu Four Title",
Tab = "Menu")]
public string MenuFourTitle { get; set; }
[DocumentTypeProperty(UmbracoPropertyType.ContentPicker,
Name = "Menu Five Link",
Description = "Menu Five Link",
Tab = "Menu")]
public string MenuFiveLink { get; set; }
[DocumentTypeProperty(UmbracoPropertyType.Textstring,
Name = "Menu Five Title",
Description = "Menu Five Title",
Tab = "Menu")]
public string MenuFiveTitle { get; set; }
}   

The sub menu document type will be used to create the secondary level menu items, as shown below:

umbraco_mega_menu_sub_menu

In here we define a property to display the grey header and then we have 5 Url and title properties to render the menu. The next thing to do now is open up the Umbraco backend and add in some data for us to render out, like so:

umbraco_mega_menu_data

The html and css…

I recommend checking out the associated project to see this in full as it’s quite complex. In the layout.cshtml, I added a reference to a file called Header.html.  In there I then use the following HTML:

@model JonDJones.BusinessLayer.ViewModel.HeaderViewModel
<ul id="oe_menu" class="oe_menu hovered">
@foreach (var page in Model.MenuItems)
{
<li class="">
<a href="@page.Url">@page.Name</a>
@if (page.GetChildren().Any())
{
<div style="z-index: 1; display: none;">
@foreach (var subMenu in page.GetChildren().Select(x => x as JonDJones.BusinessLayer.DocumentTypes.SubMenuItemDocumentType))
{
<ul>
<li class="oe_heading">@subMenu.MenuTitle</li>
@if (@subMenu.MenuOneLink != null)
{
<li><a href="@subMenu.MenuOneLink">@subMenu.MenuOneTitle</a></li>
}
@if (@subMenu.MenuTwoLink != null)
{
<li><a href="@subMenu.MenuTwoLink">@subMenu.MenuTwoTitle</a></li>
}
@if (@subMenu.MenuThreeLink != null)
{
<li><a href="@subMenu.MenuThreeLink">@subMenu.MenuThreeTitle</a></li>
}
@if (@subMenu.MenuFourLink != null)
{
<li><a href="@subMenu.MenuFourLink">@subMenu.MenuFourTitle</a></li>
}
@if (@subMenu.MenuFiveLink != null)
{
<li><a href="@subMenu.MenuFiveLink">@subMenu.MenuFiveTitle</a></li>
}
</ul>
}
</div>
}
</li>
}
</ul>

Code Example

The code above can be quite hard to wrap your head around when it’s all a flat page or text.  To make life easier, `I would recommend downloading this working code sample from my GitHub account, JonDJones.com.Umbraco.MegaMenu

Conclusion

In today’s guide, I discussed the difference between a bog standard menu that follows your websites page hierarchy and creating more complex menus.  In order to create more complex menus, it’s a good idea to create a separate section in your page hierarchy and define your own document types to render out everything you need.

In most projects I’ll usually use four document types to define my menus.   One as a container to store the menus, one document type to define the menu, one document type to define the primary navigation areas, and one to create any sub menu items.

Depending on your design, you will want to structure and design your document types accordingly, then render out the menus by iterating through the menu collection.

Jon D Jones

Software Architect, Programmer and Technologist Jon Jones is founder and CEO of London-based tech firm Digital Prompt. He has been working in the field for nearly a decade, specializing in new technologies and technical solution research in the web business. A passionate blogger by heart , speaker & consultant from England.. always on the hunt for the next challenge

More Posts

0 replies

Leave a Reply

Want to join the discussion?
Feel free to contribute!

Leave a Reply

Your email address will not be published. Required fields are marked *