Click here to Skip to main content
15,306,676 members
Articles / Productivity Apps and Services / Sharepoint / SharePoint 2013
Posted 24 Aug 2014


30 bookmarked

SharePoint 2013 Client Side Rendering: List Views

Rate me:
Please Sign up or sign in to vote.
4.96/5 (37 votes)
24 Aug 2014CPOL10 min read
All you need to know to start creating your own CSR customizations in SharePoint 2013.


In SharePoint 2013, Client Side Rendering (aka CSR) is used for rendering list views, list forms and search results. This article provides a head-start into the CSR API for list views: how CSR works, how you can use the API, and the code examples, those you can adapt for your own solutions. 

How CSR works

Unlike previous SharePoint rendering systems (XSLT in 2010 and CAML in 2007), CSR is client-side. The only thing server-side webparts do is they put a huge bulk of raw data into the page, in JSON format. This data become JS object when the page loads, and from then on the Client Side Rendering begins. 

So basically, what CSR does is it gets the JS object with raw data as input, and renders huge HTML string based on it: 

Image 1 

After HTML string is fully formed, it is inserted into the DOM.

CSR processing of the raw data is divided into stages, each represented by one overridable JS function. Each function returns its own chunk of HTML. Stages are often nested into each other. 

The stages order isn't documented, so I had to dive head first into the clienttemplates.debug.js file to figure it out. For list views, the order turns out to be the following: 

Image 2 

Group, Item and Field functions can be called many times, while View, Header, Body and Footer are called only once. 

Visually it looks like this: 

Image 3 

Stage-functions can be overriden with custom functions, thus it really helps to have this picture around when planning customizations. 

Also, there are two additional events that can be used for customization: OnPreRender and OnPostRender. These are not the part of the main process: they don't yield HTML chunks, but rather behave as ordinary events, so you can subscribe to them and execute some code at a specific moment. 

OnPreRender and OnPostRender events are shown on the full CSR diagram below: 

Image 4 

As you can see, OnPostRender is particularily useful, because it fires after the formed HTML string is inserted into DOM, so that this is the earliest moment when you can manipulate the DOM elements that were rendered by CSR. 

Using CSR API 

Main entry point of the CSR API is the following function: 


The options parameter is a JS object that contains all the necessary information for customizations. It has the following core structure:

var options = {
  OnPreRender: /* function or array of functions */,
  Templates: {
    View: /* function or string */,
    Body: /* function or string */,
    Header: /* function or string */,
    Footer: /* function or string */,
    Group: /* function or string */,
    Item: /* function or string */,
    Fields: {
      'Field1 Internal Name': {
          View: /* function or string */,
          EditForm: /* function or string */,
          DisplayForm: /* function or string */,
          NewForm: /* function or string */
      'Field2 Internal Name': {
          View: /* function or string */,
          EditForm: /* function or string */,
          DisplayForm: /* function or string */,
          NewForm: /* function or string */
      // .... and so on
  OnPostRender: /* function or array of functions */

As you can see, this structure resembles the CSR stages and events. 

Now, if I want to subscribe for the OnPreRender and OnPostRender events, I do it like this: 

  OnPreRender: function() { console.log('CSR OnPreRender'); },
  OnPostRender: [
    function() { console.log('CSR OnPostRender'); },
    function() { alert('CSR OnPostRender'); }

OnPreRender and OnPostRender accept either a function or an array of them. All provided functions will be executed whenever event is fired. 

Stage-related fields inside Templates field accept a function or a string. For example, let's add some text to the footer of the list view: 

  Templates: {
    Footer: "Hello world from <#= ctx.ListTitle #>!"

Notice the <#= ... #> tag inside the string! It automatically gets replaced with appropriate value from the context object. Context object ctx is the very object with raw data that was rendered by server-side webparts.

Result of applying this customization:

 Image 5 

As you can see, the Hello world string appeared in the footer of the list view, and also the token got replaced with the actual value (i.e. the list title).

Instead of string, function can be used for creating the same customization:

  Templates: {
    Footer: function(ctx) {
      return "Hello world from " + ctx.ListTitle + "!";

So as you can see, the function should accept the context object as the only parameter, and return the HTML string. In most cases, context object is the only parameter, but rarely, there might be additional parameters. For example, Group template receives 7 arguments.

Notice that we cannot use the <#= ... #> tokens any more, at least directly.

As you might expect, there is a lot of string generation happening in CSR, thus I find it very convenient to leverage ASP.Net Ajax String.format function for that purpose. It has same syntax as the well known String.Format from C#. ASP.Net Ajax library is deployed on every SharePoint page by default through the ScriptManager control, so you don't have to worry about that.

Previous example becomes a bit cleaner with String.format: 

  Templates: {
    Footer: function(ctx) {
      return String.format("Hello world from {0}!", ctx.ListTitle);

Now, please don't forget that RegisterTemplateOverrides call causes out-of-the-box function to be replaced by the custom function. So if you replace something, you have to understand that some functionality may be broken.

For example, if instead of Footer, we use Body in the previous code snippet, the result gets quite ugly: 

Image 6

So even if you want to replace only tiny part of the view, the limitedness of granularity provided by SharePoint may force you to end up with big amounts of code. Usually I have to copy-paste the corresponding OOTB code from clienttemplates.debug.js, and then modify it slightly.

By the way, even although Footer was initially empty in my particular case, it is normally used for paging, so if you redefine it unthinkingly, the paging functionality will disappear from your list!

One obvious solution to such situations is to use OnPostRender event and perform customizations by manipulating the just rendered DOM elements, e.g. by using jQuery or HTML5 selectors.

Calling nested templates

Now, what happens if you want e.g. manipulate order of items, not touching the items themselves?

It turns out, that during the rendering process, CSR uses the ctx object for passing some additional information to the inner functions. Including the references to all of the nested methods! 

Image 7 

So using these references, you get ability to replace top CSR templates such as View, Body and Item without replacing the subtemplates.

Primitive example code for the View template: 

  Templates: {
    View: function(ctx) {
      return ctx.RenderHeader() + ctx.RenderBody() + ctx.RenderFooter();

Example: Color coding

Let's consider a more real-world example - color coding. So for example, I want to paint green all rows from a document library that have status "Approved". 

Since there's not much of a customization here - I need just to change a css property of an existing element, - best way to accomplish this would be to use OnPostRender event and manipulate DOM elements that were rendered by CSR. 

From OnPostRender, the ctx is accessible, thus it is not a problem to determine which documents were approved (given the Approved column is included into the view). The only tricky thing is to get the ID of the element that represents the row. Here I cheated a bit, by peeking into the CSR guts and finding a function, that generates row ids (but obviously, you can also figure out these IDs from the page source and generate them manually). 

Now everything is simple: we have the element IDs, and we can acquire field values from ctx (after a short investigation I found them in the ctx.ListData.Row array). 

So here's the final code: 

  OnPostRender: function(ctx) {
    var rows = ctx.ListData.Row;
    for (var i=0;i<rows.length;i++)
      var isApproved = rows[i]["_ModerationStatus"] == "Approved";
      if (isApproved)
        var rowElementId = GenerateIIDForListItem(ctx, rows[i]);
        var tr = document.getElementById(rowElementId); = "#ada";

This will work for English portal, but better make it international. For that, you need to replace "_ModerationStatus" with "_ModerationStatus." (dot at the end!), and compare with 0.

As you can see, SharePoint and magic are still in the same tight embrace Smile | :)

But it works:

Image 9

Example: Item link 

By default, list item title links lead to view forms. What if we need them to point to edit forms?

This can be done easily with CSR, by redefining the LinkTitle field for the view.

  Templates: {
        Fields: {
           'LinkTitle': {'View':function(ctx) {
                  var url = String.format('{0}&amp;ID={1}', ctx.editFormUrl, ctx.CurrentItem.ID);
                  return String.format('<a href="{0}" onclick="EditItem2(event, \'{0}\');return false;">{1}</a>', url, ctx.CurrentItem.Title);

EditItem2 function is a global helper function that processes list item edit links in SharePoint. It is not mandatory, but I prefer use OOTB SharePoint functions wherever possible, because otherwise there is a chance to break some existing functionality.

ctx.editFormUrl is the URL of the edit form, and ctx.CurrentItem is data for the item that is being processed by the handler.

As you might have suspected, the contents of ctx aren't documented. Simplest way to assess the various fields of the ctx object is to put a breakpoint into your code and then use Watch window.

Result of performing the edit link customization of a Tasks list on my portal is shown on the following screenshot:

Image 10

Here PageType=6 represents PAGE_EDITFORM mode, as you can verify yourself on MSDN. And indeed, the link now leads straight to the list item edit form.

Applying customizations

Ok, now you know how to write the code, but how to actually apply the created customizations to the lists?

Piece of cake:

  1. Switch the page into edit mode
  2. Add Script Editor webpart right below the list view web part.
  3. Put your code into the Script Editor
  4. Save the page

That's it. 

Image 11

But of course, it's not the only way. In fact, you can put the code into the page by using any method you want - masterpage, page layout, script link, etc., just don't forget to wrap it into the SP.SOD.executeFunc call, to ensure that the clienttemplates.js file is loaded before your script is executed. 

SP.SOD.executeFunc("clienttemplates.js", "SPClientTemplates", function() {
    // ...

Targeting the list view

If you have more than one list view on the page, or if you're deploying the script throughout your site rather than to only one page, you might want to ensure, that the customizations are applied to the correct list view.

For that, you can use three additional fields of the options object:

  1. ListTemplateType - ID of the list template.
  2. ViewStyle - ID of the view style.
  3. BaseViewID - BaseViewID of the list view.


For example, if you want to customize the out-of-the-box Tasks lists, use this code: 

  Templates: {
    Footer: function(ctx) {
      return String.format("Hello world from {0}!", ctx.ListTitle);
  ListTemplateType: 171

IDs of standard list templates can be found on MSDN. Also custom list template IDs (10000 and above) can be used for lists based on such templates. 


In truth, not every SharePoint developer even knows what is view style. For simple reason: until now, they weren't really useful Smile | :)

View style of a view can be found and edited on the Modify View page: 

Image 13 

Out-of-the-box view styles are dull and ugly. Nobody uses them. From developer's point of view, they're not quite appealing either: there's no supported way of changing those captions, and there is no supported way of adding your own styles. 

But at least you can now conveniently override how they look. Hopefully MS will provide a way to change the captions too, somewhere in future. 

So to override a view style, you need it's ID. It can be acquired from the page source: 

Image 14 


BaseViewID doesn't appear in UI. You can access it in SharePoint Designer, in Schema.xml or programmatically. It is an attribute of the View element. 

By the way, do you even know what BaseViewID is? I have it explained here on SharePoint SE

Thus, using ListTemplateType, ViewStyle and BaseViewID, it is possible to target your customizations with some sort of reliability. 

Briefly about JSLink 

I find it very embarrasing when some popular bloggers use CSR and JSLink interchangeably. 

Please remember, JSLink and CSR are completely different things, and they can very well live without each other. 

Above I created CSR customizations that don't use JSLink and work fine. 

JSLink is just a way to stick a javascript file to a SharePoint object. From that moment on, wherever this object appears, the script will be deployed as well. Script definitely can be non-CSR, e.g. jQuery, knockout.js, etc. 

JSLink property was added to the following SharePoint objects in SP2013: 

  • SPContentType
  • SPField
  • SPForm
  • SPView
  • XsltListViewWebPart
  • ListFormWebPart
  • ... and some others 

So indeed, it is very convenient to use JSLink in conjunction with CSR, because the CSR script gets the ability to "travel" wherever the list view is deployed. 

Another interesting detail, is that you can deploy several scripts at once using the JSLink property. Just separate them with "|". This is a very good way to include your CSR dependencies along with the main script. 


CSR is the main rendering framework in SharePoint 2013 and thus an essential part of the system. Knowing how it works and how to use it definitely pays off. 


  • Very easy to learn. You can start creating customizations literally in 10 minutes
  • Client side => less server load
  • CSR is javascript-based. Javascript community is huge and the number of different new JS libraries is astonishing.
  • Works with apps, including sharepoint-hosted
  • Huge improvement over the XSLT in terms of readability, performance, debugability, etc. 


  • Scarcely documented
  • Sometimes requires magic skills :)
  • Unfortunately, still a long way from modern rendering frameworks, such as KnockoutJs, AngularJs, etc. 

Please note, in this article, I only explained CSR for list views. CSR is also used for displaying Quick Edit, search results and list forms. But each of these is a subject of a separate story.

I wrote series of articles regarding CSR for list forms, so if you do list forms customizations, have a look:

So good luck, and don't hesitate to drop a comment below if you have any questions!


This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


About the Author

Andrei Markeev
Finland Finland
Full stack developer, enterprise web software. Microsoft MVP, open source person, speaker, online expert.

Comments and Discussions

QuestionHow do I add the url to the specific form that I want to redirect to? Pin
soncrgh%1-Apr-20 7:08
Membersoncrgh%1-Apr-20 7:08 
QuestionColor Coding Pin
Member 1392752526-Jul-18 18:53
MemberMember 1392752526-Jul-18 18:53 
QuestionColor Coding rowss Pin
George papas10-Jul-17 21:24
MemberGeorge papas10-Jul-17 21:24 
QuestionExcellent article! Pin
Fuzuli Hameed4-Jul-17 16:46
MemberFuzuli Hameed4-Jul-17 16:46 
QuestionCSR for ListView with non-default style Pin
lalitm26-Jan-17 6:22
Memberlalitm26-Jan-17 6:22 
AnswerRe: CSR for ListView with non-default style Pin
Andrei Markeev8-Apr-17 12:26
MemberAndrei Markeev8-Apr-17 12:26 
GeneralRe: CSR for ListView with non-default style Pin
lalitm10-Apr-17 9:02
Memberlalitm10-Apr-17 9:02 
QuestionRe: CSR for ListView with non-default style Pin
sashukevich31-Jan-18 2:55
Membersashukevich31-Jan-18 2:55 
QuestionAndrei Great Article Pin
Eric Halsey13-Jan-17 4:58
MemberEric Halsey13-Jan-17 4:58 
AnswerRe: Andrei Great Article Pin
Andrei Markeev8-Apr-17 11:23
MemberAndrei Markeev8-Apr-17 11:23 
QuestionCSR and Content Type Pin
JoshKorn22-Nov-16 4:39
MemberJoshKorn22-Nov-16 4:39 
AnswerRe: CSR and Content Type Pin
Andrei Markeev24-Nov-16 4:44
MemberAndrei Markeev24-Nov-16 4:44 
QuestionQuick Edit Mode Pin
Member 1171720325-Aug-16 3:31
MemberMember 1171720325-Aug-16 3:31 
AnswerRe: Quick Edit Mode Pin
Andrei Markeev24-Nov-16 4:48
MemberAndrei Markeev24-Nov-16 4:48 
QuestionCSR and Checkbox Values Pin
D Morris6-Jun-16 2:58
MemberD Morris6-Jun-16 2:58 
AnswerRe: CSR and Checkbox Values Pin
Andrei Markeev12-Oct-16 7:51
MemberAndrei Markeev12-Oct-16 7:51 
QuestionCSR on Content Editor Webpart Pin
VJ_K14-Dec-15 10:42
MemberVJ_K14-Dec-15 10:42 
AnswerRe: CSR on Content Editor Webpart Pin
Andrei Markeev12-Oct-16 6:24
MemberAndrei Markeev12-Oct-16 6:24 
QuestionHow to return the default list item template Pin
Member 121200979-Nov-15 4:23
MemberMember 121200979-Nov-15 4:23 
AnswerRe: How to return the default list item template Pin
Andrei Markeev12-Oct-16 8:14
MemberAndrei Markeev12-Oct-16 8:14 
QuestionMultiple OnPreRender executions on a List view Pin
Member 1196833629-Oct-15 12:51
MemberMember 1196833629-Oct-15 12:51 
AnswerRe: Multiple OnPreRender executions on a List view Pin
Andrei Markeev1-Nov-15 10:15
MemberAndrei Markeev1-Nov-15 10:15 
GeneralRe: Multiple OnPreRender executions on a List view Pin
Member 119683361-Nov-15 14:25
MemberMember 119683361-Nov-15 14:25 
QuestionViewStyle settings Pin
Member 119683368-Sep-15 3:25
MemberMember 119683368-Sep-15 3:25 
AnswerRe: ViewStyle settings Pin
Andrei Markeev8-Sep-15 5:43
MemberAndrei Markeev8-Sep-15 5:43 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.