Search-Driven Twitter Bootstrap Carousel in SharePoint 2013

Content Search web part introduced in SharePoint 2013 is a powerful tool that lets you easily retrieve and customize the appearance of search results without ever writing a single line of server-side code. In this post I’ll show how to display items from a SharePoint list in a Twitter Bootstrap Carousel on any page of your site using a Content Search web part and a custom control and item display templates.

  1. First thing we need to do is to create a SharePoint list that will contain the items to be displayed in the carousel. Let’s start by creating the site columns below.
    1. Navigate to Site Settings > Site columns > Create
    2. CarouselBody site column is going to hold the text to be displayed within each carousel slide.
      1. Name: CarouselBody
      2. Type: Full HTML content with formatting and constraints for publishing
      3. Group: Contoso
      4. Require that this column contains information: Yes
    3. CarouselImage site column will contain the image to be displayed as the slide background.
      1. Name: CarouselImage
      2. Type: Image with formatting and constraints for publishing
      3. Group: Contoso
      4. Require that this column contains information: Yes
    4. At this point the site columns should look something like this:
  2. Next, we need to create a content type
    1. Navigate to Site Settings > Site content types > Create
    2. The Carousel content type will group the site columns together
      1. Name: Carousel
      2. Parent Content Type: Item
      3. Group: Contoso
    3. Add the site columns
      1. Add from existing site columns
      2. Select columns from: Contoso
      3. Columns to add: CarouselBody, CarouselImage
    4. The content type now should look similar to this:
  3. Now it’s time to create the SharePoint list.
    1. Site Contents > add an app > Custom List
      1. Name: Carousel
    2. Enable content type management for the list.
      1. List Settings > Advanced settings
      2. Allow management of content types?: Yes
    3. Add the Carousel content type to the list content types
      1. List Settings > Content Types > Add from existing site content types
      2. Group: Contoso
      3. Content types to add: Carousel
    4. Remove the default Item content type from the list
      1. List Settings > Content Types > Item > Delete this content type
    5. The list settings should now be as below:
  4. Finally, we are ready to add some carousel items to the list.
  5.  Once the items are added, let’s go ahead and run a full crawl. The managed properties for each column in the list will be created automatically.
    1. Central Administration > Application Management > Manage service applications
    2. Search Service Application > Content Sources > Local SharePoint Sites > Start Full Crawl
  6. When the crawl is complete we can verify that all of the information we need is in the search index by running a REST API search query.
    1. http://intranet.contoso.com/_api/search/query?querytext=’contenttype:carousel’&selectproperties=’Title,CarouselBodyOWSHTML,CarouselImageOWSIMGE’
    2. The results should match the screenshot below:
  7. Before we move on to the next step, we need to download the jQuery library and Twitter Bootstrap Carousel package and upload those to the Site Assets document library.
    1. Download jQuery: http://code.jquery.com/jquery-1.8.2.min.js
    2. Download Bootstrap: http://twitter.github.com/bootstrap/customize.html
      1. Choose components: Carousel
      2. Select jQuery plugins: Carousel
    3. Site Contents > Site Assets
    4. Upload Document: jquery-1.8.2.min.js
    5. Upload Document: bootstrap.min.css
    6. Upload Document: bootstrap.min.js
    7. The contents of the Site Assets document gallery should look something like this:
  8. At this point we have the content we need available and can now start developing the custom display templates. We’ll do that by copying and editing some of the standard display templates that come with SharePoint 2013 and located in the master pages gallery.
    1. Site Settings > Master pages > Display Templates > Content Web Parts
    2. Control_List.html > Download a Copy
    3. Save As: Control_CarouselList.html
    4. Replace the content of the file with the following:
      <html xmlns:mso="urn:schemas-microsoft-com:office:office" xmlns:msdt="uuid:C2F41010-65B3-11d1-A29F-00AA00C14882">
      
      <head>
      
      <title>Carousel List</title>
      
      <!--[if gte mso 9]><xml>
      
      <mso:CustomDocumentProperties>
      
      <mso:TemplateHidden msdt:dt="string">0</mso:TemplateHidden>
      
      <mso:MasterPageDescription msdt:dt="string">This is a Carousel Control Display Template that will list the items.</mso:MasterPageDescription>
      
      <mso:ContentTypeId msdt:dt="string">0x0101002039C03B61C64EC4A04F5361F385106601</mso:ContentTypeId>
      
      <mso:TargetControlType msdt:dt="string">;#Content Web Parts;#</mso:TargetControlType>
      
      <mso:HtmlDesignAssociated msdt:dt="string">1</mso:HtmlDesignAssociated>
      
      </mso:CustomDocumentProperties>
      
      </xml><![endif]-->
      
      </head>
      
      <body>
      
          <!--
      
                  Warning: Do not try to add HTML to this section. Only the contents of the first <div>
      
                  inside the <body> tag will be used while executing Display Template code. Any HTML that
      
                  you add to this section will NOT become part of your Display Template.
      
          -->
      
          <script>
      
              $includeLanguageScript(this.url, "~sitecollection/_catalogs/masterpage/Display Templates/Language Files/{Locale}/CustomStrings.js");
      
      		$includeCSS(this.url, "~sitecollection/SiteAssets/bootstrap.min.css");
      
      		$includeScript(this.url, "~sitecollection/SiteAssets/jquery-1.8.2.min.js");
      
          </script>
      
          <!--
      
              Use the div below to author your Display Template. Here are some things to keep in mind:
      
              * Surround any JavaScript logic as shown below using a "pound underscore" (#_ ... _#) token
      
              inside a comment.
      
              * Use the values assigned to your variables using an "underscore pound equals"
      
              (_#= ... =#_) token.
      
          -->
      
          <div id="Control_CarouselList">
      
      <!--#_
      
      if (!$isNull(ctx.ClientControl) &&
      
          !$isNull(ctx.ClientControl.shouldRenderControl) &&
      
          !ctx.ClientControl.shouldRenderControl())
      
      {
      
          return "";
      
      }
      
      ctx.ListDataJSONGroupsKey = "ResultTables";
      
      var $noResults = Srch.ContentBySearch.getControlTemplateEncodedNoResultsMessage(ctx.ClientControl);
      
      var noResultsClassName = "ms-srch-result-noResults";
      
      var ListRenderRenderWrapper = function(itemRenderResult, inCtx, tpl)
      
      {
      
          var iStr = [];
      
          iStr.push(itemRenderResult);
      
          return iStr.join('');
      
      }
      
      ctx['ItemRenderWrapper'] = ListRenderRenderWrapper;
      
      ctx.OnPostRender = function() {
      
      	$("div.item").first().addClass("active");
      
      	$.getScript(SP.PageContextInfo.get_siteServerRelativeUrl() + "SiteAssets/bootstrap.min.js", function() {
      
      		$(".carousel").carousel();
      
      	});
      
      };
      
      _#-->
      
        <div id="myCarousel" class="carousel slide">
      
      	<div class="carousel-inner">
      
                  _#= ctx.RenderGroups(ctx) =#_
      
      	</div>
      
      	<a class="left carousel-control" href="#myCarousel" data-slide="prev">&lsaquo;</a>
      
      	<a class="right carousel-control" href="#myCarousel" data-slide="next">&rsaquo;</a>
      
        </div>
      
      <!--#_
      
      if (ctx.ClientControl.get_shouldShowNoResultMessage())
      
      {
      
      _#-->
      
              <div class="_#= noResultsClassName =#_">_#= $noResults =#_</div>
      
      <!--#_
      
      }
      
      _#-->
      
          </div>
      
      </body>
      
      </html>
      
      
    5. The carousel control display template is ready so we can upload it to the same location in the master pages gallery.
      1. Site Settings > Master pages > Display Templates > Content Web Parts
      2. Upload Document: Control_CarouselList.html
    6. You should see the Control_CarouselList.js file automatically generated by SharePoint 2013:
  9. The next step is to create an item display template for the carousel slides.
    1. Similar to the control display template created earlier, we are going to copy and edit a standard item display template.
      1. Site Settings > Master pages > Display Templates > Content Web Parts
      2. Item_PictureOnTop.html > Download a Copy
      3. Save As: Item_Carousel.html
    2. Replace the file content with the following:
      <html xmlns:mso="urn:schemas-microsoft-com:office:office" xmlns:msdt="uuid:C2F41010-65B3-11d1-A29F-00AA00C14882">
      <head>
      
      <title>Carousel item</title>
      
      <!--[if gte mso 9]><xml>
      
      <mso:CustomDocumentProperties>
      
      <mso:TemplateHidden msdt:dt="string">0</mso:TemplateHidden>
      
      <mso:ManagedPropertyMapping msdt:dt="string">'Image'{Image}:'CarouselImageOWSIMGE','Heading'{Heading}:'Title','Body'{Body}:'CarouselBodyOWSHTML'</mso:ManagedPropertyMapping>
      
      <mso:MasterPageDescription msdt:dt="string">This Item Display Template will show a carousel item.</mso:MasterPageDescription>
      
      <mso:ContentTypeId msdt:dt="string">0x0101002039C03B61C64EC4A04F5361F385106603</mso:ContentTypeId>
      
      <mso:TargetControlType msdt:dt="string">;#Content Web Parts;#</mso:TargetControlType>
      
      <mso:HtmlDesignAssociated msdt:dt="string">1</mso:HtmlDesignAssociated>
      
      </mso:CustomDocumentProperties>
      
      </xml><![endif]-->
      
      </head>
      
      <body>
      
          <!--
      
                  Warning: Do not try to add HTML to this section. Only the contents of the first <div>
      
                  inside the <body> tag will be used while executing Display Template code. Any HTML that
      
                  you add to this section will NOT become part of your Display Template.
      
          -->
      
          <script>
      
              $includeLanguageScript(this.url, "~sitecollection/_catalogs/masterpage/Display Templates/Language Files/{Locale}/CustomStrings.js");
      
          </script>
      
          <!--
      
              Use the div below to author your Display Template. Here are some things to keep in mind:
      
              * Surround any JavaScript logic as shown below using a "pound underscore" (#_ ... _#) token
      
              inside a comment.
      
              * Use the values assigned to your variables using an "underscore pound equals"
      
              (_#= ... =#_) token.
      
          -->
      
          <div id="Item_Carousel">
      
      <!--#_
      
      var carouselImage = $getItemValue(ctx, "Image");
      
      var carouselHeading = $getItemValue(ctx, "Heading");
      
      var carouselBody = $getItemValue(ctx, "Body");
      
      _#-->
      
      	  <div class="item">
      
      		_#= carouselImage.value =#_
      
      		<div class="carousel-caption">
      
      		  <h4>_#= carouselHeading =#_</h4>
      
      		  <p>_#= carouselBody =#_</p>
      
      		</div>
      
      	  </div>
      
          </div>
      
      </body>
      
      </html>
      
      
    3. Upload the custom item display template to the master pages gallery.
      1. Site Settings > Master pages > Display Templates > Content Web Parts
      2. Upload Document: Item_Carousel.html
    4. Verify that the associated Item_Carousel.js was successfully generated:
  10. At last, everything is in place and we can now add a Content Search web part to the page.
    1. Page > Edit
    2. Insert > Web Part > Content Rollup > Content Search
    3. Configure the web part to fetch carousel items from the search index and use the custom display templates created earlier.
      1. Edit Web Part
      2. Change Query
        1. Select a query: Items matching a content type
        2. Restrict by content type: Carousel
      3. Display Templates
        1. Control: Carousel List
        2. Item: Carousel Item
      4. Appearance
        1. Width: 830px (set to the width of your carousel images)
    4. Page > Save

At this point you should see the Twitter Bootstrap Carousel on the page displaying items from the Carousel SharePoint list.

  • PseudoDaemon

    Very good. Works perfectly! Thank you. I do have a question — I added an additional content type field of type “hyperlink” so I can specify a url and a description for the url. I added the property to the ManagedPropertyMapping list , but I cannot access the URL hyperlink value nor the description text value in the display template. Any tips/examples? Thanks so much.

    • HerrFledermaus

      Any news on this please?

  • Vassili Altynikov

    First thing I would do is confirm that the managed property value actually gets populated. A quick way to do that is to add the managed property name to the selectproperties list in step 6 above and take a look at the XML results.
    I’ve also noticed that the content search web part doesn’t always recognize new managed properties added to the ManagedPropertyMapping list after the item display template has been selected. A quick test would be to select one of the out-of-the-box item display templates and then change back to your carousel item display template. If that still doesn’t work then try deleting and re-adding the web part to the page and see if that makes any difference.

  • Bret Siakel

    Hi,

    First, this was a MAJOR help. However, when following the steps, I noticed an error that prevented proper display. In this area of the control template:

    ctx.OnPostRender = function() {
    document.querySelector(“div.item”).classList.add(“active”);
    $.getScript(SP.PageContextInfo.get_siteServerRelativeUrl() + “/SiteAssets/bootstrap.min.js”, function() {
    $(“.carousel”).carousel();

    You are missing a “/” before “SiteAssets/bootstrap.min.js” The script cannot find the bootstrap.min.js

    Again, you rock.

    Thanks,
    -Bret

    • Vassili Altynikov

      Thanks for the feedback Bret! I’m glad you found the post useful.

      You are absolutely right about the “/”. In my example I deployed to a site collection at the root of the web application so the SP.PageContextInfo.get_siteServerRelativeUrl() simply returned “/” but you do need to add it if not using the root site collection.

  • Emmanuel

    Hi Vassili !
    Tanks for the post. It works well in my side (IE10 and other browsers), but with IE9 I have a bug:

    “Unable to get property ‘add’ of undefined or null reference (OnPostRender: )”, related I think to this line of the code :
    document.querySelector(“div.item”).classList.add(“active”);

    I do not have a workaround for the moment. If you have time, can you have a look on it ?

    regards

    Emmanuel

    • Vassili Altynikov

      Hi Emmanuel,

      Thanks for your feedback! You are absolutely correct, I get the same error in IE9. Using a jQuery selector is more reliable in this case, simply replace the line of code with this: $("div.item").first().addClass("active");

      • Emmanuel

        Thanks a lot Vassili. It works now. Your post was very helpful for me ! Have a good week.

  • hi

    hi

    I am able to use above code. But after adding this Content search web part with above templates, I am able to see 3 images in the out put. It suppose to show only one., when I click next it has to show other one.
    Please suggest me, am I missing anything.

    • Vassili Altynikov

      Sounds like the JavaScript code to initialize the carousel doesn’t execute on page load for you for some reason. You’ll need to check for any JavaScript errors on the page to troubleshoot the issue.

  • Tomas

    Hello,
    Thanks for this great guide!
    One question, when I upload my displaytemplates to the master page gallery, the corresponding js files are not auto generated. Why is that? I am doing this on a team site template. Must it be a publishing site?

  • Vassili Altynikov

    Hi Tomas,
    I’ve only tried this on a publishing site so that’s probably what it is. You can also try activating the publishing feature on the team site to see if that helps.
    Thanks!

  • Nnabu

    Thanks for this post. After uploading the template files I get an error with the Control list that there is an syntax error in Control_CarouselList.js or that it does not exist.

    The only change I made was using a different set of managed properties and that was in the Item template and that works when I try with other control list template.

    Any ideas where this syntax error could have entered the file?

    Many thanks.

    • Vassili Altynikov

      @Nnabu – I suspect that may be a browser copy/paste issue. I’d suggest you download a copy of the out-of-the-box Control_List.html, rename it to Control_CarouselList.html, upload to the display templates library and see if that works. If it does then start replacing the file content one section at a time.

  • Rob

    Thanks for posting this. Though I am having one problem, the search query or edit webpart doesn’t return any values for CarouselImageOWSIMGE or CarouselBodyOWSHTML. In the web part when I select diagnostic to see the values of these two fields they are empty.
    So the carousel is blank because it can’t find the images.
    Thanks
    Rob

    • Vassili Altynikov

      @Rob, do you see any values for those managed properties when running a search query through REST API, i.e. http://intranet.contoso.com/_api/search/query?querytext=’contenttype:carousel’&selectproperties=’Title,CarouselBodyOWSHTML,CarouselImageOWSIMGE’
      Also, it is very important that site column types are “Publishing HTML” and “Publishing Image”.
      Have you completed a Full Crawl after adding items to the Carousel list?

      • Rob

        Thanks for the quick response. I verified the column types are correct.
        Though I do NOT see the manage properties through the search rest api. My search response is much longer and the Carousel columns are not in the response. I’m not sure if this is related but I do see in the response the rendertemplate is Item_Default.js. If you email me I can send you the response XML. Thanks

      • Rob

        And yes I completed a full crawl a verified it in the crawl logs.

    • Vassili Altynikov

      Can you confirm if your carousel fields were created as “site columns” at the site collection level? SharePoint search automatically creates managed properties for site columns only: http://technet.microsoft.com/en-us/library/jj613136(v=office.15).aspx

      • Rob

        This appears to be something wrong with search. I tested on creating other site columns and used the SharePoint Search Query tool to test out what managed properties are returned. Even though they get properly created in the Search Schema, for some reason they are not being crawled and/or returned when queried. Any ideas?

    • Vassili Altynikov

      Thanks for the update! I’m glad you were able to fix the problem by resetting the search index.

  • Kris

    There seems to be some issues with pasting code into the comments section.

    Here is a pastebin link:

    http://pastebin.com/bAP885L9

    This code will make the carousel responsive. Modify widths as you see fit.

    • Vassili Altynikov

      @Kris, thanks for providing the code snippet to adjust the carousel size based on the window size! Another way to approach that would be through CSS media queries.

  • Tim

    Hello Vassili,

    I was able to get things setup but I am getting the error:
    Something went wrong
    The details indicate:
    One or more of the following resource files failed to load: •/_catalogs/masterpage/display templates/language files/en-US/customstrings.js?ctag=1115$$15.0.4420.1017
    •/_catalogs/masterpage/display templates/content web parts/.~sitecollection/siteassets/jquery-1.8.3.min.js?ctag=1115$$15.0.4420.1017

    I have been troubleshooting the path but nothing seem to clear this issue. Do you have any suggestions?

    Thank you again for this post. Very excited about seeing this in action.

    Sincerely,
    Tim

    • Vassili Altynikov

      Hi Tim,

      The jQuery script URL doesn’t look right in your error message. Take a look at Control_CarouselList.html file content and specifically the “script” section and confirm the URLs to each of the file references there. If file locations appear to be correct then try replacing the $includeCSS and $includeScript with static “link” and “script” tags to see if that makes a difference.

      -Vassili

      • Tim

        Hello Vassili,

        Thank you so much for your quick response. You were right on the mark. The Slider is now displaying correctly. Thank you again!

        Sincerely,
        Tim

        Here was the fix.

        Issue:
        $includeCSS(this.url, "http://servername/SiteAssets/bootstrap.min.css");
        Fix:

        • Tim

          Apparently my fix didn’t come through:

          • Tim

            Site must be blocking the code block:

          • Vassili Altynikov

            Yes, unfortunately you can’t use many types of HTML tags in the comments due to security restrictions. You can enter an HTML-encoded version if you’d like.

            Thanks!

  • Paul

    I also need to add an indicator, so little help

  • Ricardo

    Hi all,

    nice tutorial, and it works too 😉

    Just a few questions, if I may:

    1. Is it supposed to have that fancy look like on the last picture? Because I cannot download the according css? Mine works, but it looks awfull.

    2. Can we put a button on each slide with a link on it?

    Thanks and sorry for the noob questions.

    • Vassili Altynikov

      Hi Ricardo,

      Thanks for the feedback!

      In response to your questions:
      1. It sounds like the CSS file doesn’t load for some reason. Try replacing the $includeCSS in the control template with a standard CSS link to bootstrap.min.css.
      2. There are ways to customize the Bootstrap Carousel. Please refer to their documentation page: http://getbootstrap.com/javascript/#carousel. As far as the links go, you can add a URL field to the content type and use it in the item display template. For example, use var linkURL = $getItemValue(ctx, "Link URL"); to retrieve the list item URL.

      Thanks!

      • HerrFledermaus

        Any luck Ricardo?

  • HerrFledermaus

    Hello all, are there any files available for download for this project? Or any help regarding on how to implement an hyperlink for each news-slide would help me out. Thanks for the splendid tutorial !

    • Hi @herrfledermaus:disqus, would the hyperlinks come from a field in the same SharePoint list?

      • Fledermaus

        Well, I’m gonna try to follow your tutorial and do it the proper way. I want it as a field in the same SharePoint list, as an extra on top of title, description and image. If I understand well, I will have to add a site column, add it to the SharePoint list and using ‘var ….’ declare it in the item_carousel.html thingy. And of course I’ll need to do some proper css formatting on the slider. I will keep you informed and explain everything I did here. If I succeed 😉
        Thanks for your quick answer !

        • You are definitely on the right track. Just one thing to consider when you create the link field – if you create it as a Publishing Hyperlink type, the entire anchor tag content will get stored in the managed property value. If all you need is the link URL, you may want to create the field as Single Line of Text which will make it easier to generate your desired HTML markup in the item display template.

          • HerrFledermaus

            Sorry, was on vacation. I’m on it right now, here’s the plan:
            1. create site column called CarouselHyperlink as a single line of text
            2. include the site column CarouselHyperlink in the Carousel list
            3. adjust the item_carousel.html thing to include the link (and make it ‘clickable’), so I will have to add somthing like:

            var linkURL = $getItemValue(ctx, “CarouselHyperlink”);

            Here we go 😉

          • HerrFledermaus

            And it works. But I get an error stating:

            Server Error in ‘/’ Application.

            A potentially dangerous Request.Path value was detected from the client (<).

            But that's security, I guess, since I am referring to external websites.

          • HerrFledermaus

            Well, something is still wrong, it doesn’t translate the correct url but instead shows the description…

          • HerrFledermaus

            Here is what a added or changed in the item_carousel.html file:

            ‘Image'{Image}:’CarouselImageOWSIMGE’,’Heading'{Heading}:’Title’,’Body'{Body}:’CarouselBodyOWSHTML’,’Hyperlink'{Hyperlink}:’CarouselHyperlinkOWSHTML’

            var carouselHyperlink = $getItemValue(ctx, “Hyperlink”);

            and then a href html code within a tags to refer to the link, but the href in the code stays href=”” so there must be something wrong with the mapping… 🙁

          • What is the name of the new site column? CarouselHyperlink? If you created it as a single line of text then the automatically generated managed property name should be CarouselHyperlinkOWSTEXT. You can find the naming conventions here: https://technet.microsoft.com/en-us/library/jj613136(v=office.15).aspx

            Did you run a full crawl after creating the new site column?

          • Fledermaus

            The crawl. THE CRAWL !! I always forget the crawl… Thanks Vassili, I will start a crawl but that may take a while. I’ll keep you posted.

          • HerrFledermaus

            Hi Vassili, just to let you know that everything works as planned now. Thank you very much for all the help !!

          • Great! I’m glad I was able to help.