Before Sitecore 9 Dynamic Placeholders were only available with some custom code: the community had produced different implementations for that, such as the Integrated Dynamic Placeholders from Mark Servais and Jamie Stump. One of the new cool features of Sitecore 9 are the OOTB Dynamic Placeholders, with some great features we can easily imagine great implementations to our content editors.
This article shows a possible approach to implement a Bootstrap-Compatible Grid System taking advantage of the new features of Dynamic Placeholders to build a simple yet flexible Grid System. With that, you will be able to create complex page layouts in Experience Editor. Only a couple Views (cshtml files) were enough for this implementation, and I am pretty sure you can end up with a single view if you want. So, let’s get started!
A quick look at the Bootstrap Grids markup shows its very simple:
<div class="container"> <div class="row"> <div class="col"></div> </div> </div>
Of course, if you want multiple columns and rows you will need to add more <div class=“col”> and <div class=”row”>
So, the following markup:
<div class="container">
<div class="row">
<div class="col">
1 of 2
</div>
<div class="col">
2 of 2
</div>
</div>
</div>
Gives you a grid like this:
Pretty simple, right?
You can also configure multiple settings at your rows and columns (such as alignment and sizes) just by adding different classes. The following markup, for instance:
<div class="container">
<div class="row">
<div class="col">
1 of 3
</div>
<div class="col-6">
2 of 3 (wider)
</div>
<div class="col">
3 of 3
</div>
</div>
</div>
Renders a grid like this:
The class “col-6” added to the middle column makes it twice wide as the other two columns. Bootstrap handles grid columns as 12 equal blocks - 6 in our example means 50% of available space. The other two columns will adjust to the remaining space, and they do that equally - 25% each.
Bootstrap Grids also supports responsive design, as described in Responsive Classes. We are taking advantage of these classes in our implementation, so content editors will be able to build responsive grid sets directly in Experience Editor.
Not surprisingly, Content Editors will have some renderings to add to their placeholders. When added to a page, these renderings will offer a basic markup with additional placeholders at respective columns, where your actual components will be added. Multiple renderings can be nested to create complex page layouts, and everything can be responsive (or not).
There are two basic types of components we are going to implement:
A single rendering, injecting a basic Bootstrap <div class=”container”>
<div class="container">
{placeholder}
</div>
Multiple renderings, each of them injecting a different markup, according to the specific purpose. A Single Column Container, for instance, will render something like:
<div class="row">
<div class="col">{placeholder}</div>
</div>
As you may guess, a “Simple Container” is supposed to be used as the parent rendering of one or more Column Containers, but nothing will stop you from breaking this rule if you want to take advantage of this grid system outside of the Bootstrap Grid scenarios.
Editors will simply add a rendering to a placeholder, it is rendered and new placeholders will appear. Make sure to adjust Allowed Controls properly, so you have all controls you need at your placeholders. Our sample solution (link here) comes with some pre-defined placeholders, but you can easily change and expand it according to your needs.
By using the Grid System Editors can visually create grids like these:
Our solution comes with a set of predefined classes, enough for us to implement the whole Grid System, but you can easily add your custom classes by adding new items to these folders. You can find the root item at /sitecore/system/Modules/Grids.
The only field the Css Items have is the Css Class field, and we use Name and Display Name to offer a more meaningful description to content authors.
This implementation is really basic and somehow limited, but you can think on ways to make it more fun. With some custom code you could have, for instance, some Site-Level classes that will only be available at your specific site (Hint: use the getLookupSourceItems pipeline to implement your logic for custom Field sources).
These classes are available for editors due to custom Parameter Templates that we created under /sitecore/templates/User Defined/Grids/Parameters. Take for instance the _Simple Container Parameters template, used at the Simple Container:
Beside the checkbox to hide the whole container, we also have a Multilist field with its source pointing to one of our CSS roots, which will populate the dialog accordingly.
Important: Sitecore does not support Rendering Parameters with spaces, so we are naming fields without spaces, then adjusting both their Display Name and Title fields so it looks good for the users. We are also setting up help texts so they are self-explanatory:
These Parameter Templates are then referred at our renderings (found under /sitecore/layout/Renderings/Grids). Back to the Simple Container example, this is how this rendering is setup:
So here is a complete list of the available renderings:
Except for Simple Container, all the rest have their “Responsive” and “Unresponsive” versions the editor can switch by using “Replace Component”, as previously explained in this article.
When you try to replace a rendering, you will notice the current mode is respected. A Single Column Container (responsive) can be replaced by other variations of “Responsive” Containers, and also to the Single Column Unresponsive, its own “Unresponsive” version:
If we switch this grid to its Unresponsive version, variations of the Unresponsive Containers are available for replacement along with its Responsive version, enabling the editor to switch it back.
Now that you know how the grid system works, let’s deeper dive into the implementation itself. We will start from the easier Simple Container:
We already covered this one. Stored at /sitecore/layout/Renderings/Grids/Simple Container this rendering has:
This view is at \Views\Grid\SimpleContainer.cshtml – you can see the whole code here (link here), but the most important parts are:
The placeholder
@Html.Sitecore().DynamicPlaceholder("gridcontainer", CreateWrapper)
And the CreateWrapper method:
Let’s break this into details:
We also need to declare our two providers as private variables we can use:
private readonly ICssClassProvider _cssClassProvider = new CssClassRepository();
private readonly IParameterTemplatesProvider _parameterTemplatesService = new ParameterTemplatesProvider();
We now have a fully functional Simple Container rendering, injecting Css Classes and showing/hiding the wrapper div as the content editor configures.
The rest of implementation will be covered by the view \Views\Grid\Multicolumn.cshtml. The components we have left to build will simply inject a <div class=”row”> (or hide it according to configurations) with one or multiple <div class=”col”> inside. Again, all classes can be customized as well.
We open our view with some code to retrieve the number or columns to create:
// Number of Columns
var parameterTemplatesProvider = new ParameterTemplatesProvider();
var columns = parameterTemplatesProvider.GetParameter<int>(RenderingContext.Current.Rendering.RenderingItem, "columns");
if (columns == 0)
{
columns = 2;
}
Once again, we are using our ParameterTemplatesProvider to get a parameter value, but this time we are using the current RenderingItem. This way we can specify a number of columns to render directly at the Rendering Item, at the Parameters field:
Next, we drop our Dynamic Placeholder:
@Html.Sitecore().DynamicPlaceholder("gridcolumn", CreateWrapper, columns)
And the CreateWrapper method:
Beside the things we covered at the first view, let’s check what we get:
Yes, this is all we need to support one to infinite columns! From now on we can progress without coding, so let me bring the specifics of each rendering.
Rendering item is located at /sitecore/layout/Renderings/Grids/Fifty Fifty Container and it has:
The parameters template we are using is inherits from _Multicolumn Equal Sizes Parameters the following fields:
_Standard Values of our _Fifty Fifty Parameters template will also have some predefined classes for Row and Columns. This is how we make our rendering comes pre-populated and looking as it should by default:
The 50/50 Unresponsive Container variation is even simpler, it uses _Multicolumn Equal Sizes Parameters directly, and inject the standard “col” class in all columns.
These are also 2 columns containers, but now we need to inject different classes in the left and right columns. We have two renderings, Left Rail Container and Right Rail Container, each one pointing to their respective parameter templates “_Left Rail Parameters” and “_Right Rail Parameters”. These two inherits from _Two Columns Parameters the following fields:
_Standard Values of our _Left Rail Parameters template has:
_Right Rail Parameter’s _Standard Values has Columns 1 and 2 with inverse values as _Left Rail Parameters.
Their respective Unresponsive variations makes use of two specific Parameter Templates, _Left Rail Unresponsive Parameters and _Right Rail Unresponsive Parameters. At each of the two columns, they use the unresponsive classes “col-4” (33.3%) and “col-8” (66.6%) to setup their widths.
Remaining Renderings will follow the same pattern, so we will just present them briefly and later provide a full grid with all Renderings and their specific setups.
Both renderings have 3 columns, however the first has 3 equal columns and the second has a bigger column at the middle.
This rendering will bring 4 equally sized columns
Here is a full list of our Renderings and their setups:
Rendering |
# of Cols |
View |
Parameters |
CSS Col 1 |
CSS Col 2 |
CSS Col 3 |
CSS Col 4 |
Simple Container |
1 |
SimpleContainer.cshtml |
_Simple Container Parameters |
container |
|
|
|
Single Column Container |
1 |
Multicolumn.cshtml |
_Single Column Parameters |
col |
|
|
|
Single Column Unresponsive Container |
1 |
Multicolumn.cshtml |
_Single Column Parameters |
col |
|
|
|
Fifty Fifty Container |
2 |
Multicolumn.cshtml |
_Fifty Fifty Parameters |
col-lg-6 col-md-6 col-sm-6 col-xs-12 |
col-lg-6 col-md-6 col-sm-6 col-xs-12 |
|
|
Fifty Fifty Unresponsive Container |
2 |
Multicolumn.cshtml |
_Multicolumn Equal Sizes Parameters |
col |
|
|
|
Left Rail Container |
2 |
Multicolumn.cshtml |
_Left Rail Parameters |
col-lg-4 col-md-4 col-sm-4 col-xs-12 |
col-lg-8 col-md-8 col-sm-8 col-xs-12 |
|
|
Left Rail Unresponsive Container |
2 |
Multicolumn.cshtml |
_Left Rail Unresponsive Parameters |
col-4 |
col-8 |
|
|
Right Rail Container |
2 |
Multicolumn.cshtml |
_Right Rail Parameters |
col-lg-8 col-md-8 col-sm-8 col-xs-12 |
col-lg-4 col-md-4 col-sm-4 col-xs-12 |
|
|
Right Rail Unresponsive Container |
2 |
Multicolumn.cshtml |
_Right Rail Unresponsive Parameters |
col-8 |
col-4 |
|
|
Three Column Container |
3 |
Multicolumn.cshtml |
_Three Equal Columns Parameters |
col-lg-4 col-md-4 col-sm-12 col-xs-12 |
col-lg-4 col-md-4 col-sm-12 col-xs-12 |
col-lg-4 col-md-4 col-sm-12 col-xs-12 |
|
Three Column Unresponsive Container |
3 |
Multicolumn.cshtml |
_Multicolumn Equal Sizes Parameters |
col |
col |
col |
|
Main Container with Rails |
3 |
Multicolumn.cshtml |
_Main with Rails Parameters |
col-lg-3 col-md-3 col-sm-3 col-xs-12 |
col-lg-6 col-md-6 col-sm-6 col-xs-12 |
col-lg-3 col-md-3 col-sm-3 col-xs-12 |
|
Main Container Unresponsive with Rails |
3 |
Multicolumn.cshtml |
_Main with Rails Unresponsive Parameters |
col-3 |
col-6 |
col-3 |
|
Four Column Container |
4 |
Multicolumn.cshtml |
_Four Equal Columns Parameters |
col-lg-3 col-md-3 col-sm-6 col-xs-12 |
col-lg-3 col-md-3 col-sm-6 col-xs-12 |
col-lg-3 col-md-3 col-sm-6 col-xs-12 |
col-lg-3 col-md-3 col-sm-6 col-xs-12 |
Four Column Unresponsive Container |
4 |
Multicolumn.cshtml |
_Multicolumn Equal Sizes Parameters |
col |
col |
col |
col |
Creating rendering variations of all kinds is now just a matter of creativity and will not take more than creating a new Rendering and, in some cases, its respective Parameters Template.
You can have access to the source code at Nishtech’s Git Repository:
https://bitbucket.org/nishtechinc/dynamicplaceholdergrids
Feel free to download and contribute as much as you want. We are glad to see your pull requests coming!