Setting Up a DVWP to Use jQueryUI Accordion and Tabs

SPXSLTCarlos Nunes-Ueno posted some XSL you can use in a DVWP to the SPXSLT Codeplex Project a while back which allows you to easily utilize the jQueryUI accordion and tabs functions. I asked him if he’d mind if I did a blog post on it, and he agreed. (If you happen to read the thread, I admit that I had just gotten back from vacation at the time and thought that the post came from the SPServices Discussions. That’s why I sound confused – I was.)

Here’s what Carlos told me about himself:

I’ve been working with SharePoint pretty much exclusively for the past year.  I work for a major online retailer on internally facing sites and I’ve been focused primarily on getting processes off paper.  My previous background is mainly in MS Access.  I’m still working on the ins and outs of SharePoint and trying to wring as much functionality as I can out of it.  I have found jQuery and jQueryUI to be extremely useful tools for that.

Accordions and tabs are two of the popular widgets offered by jQueryUI. In case you haven’t seen them in action, here are some simple examples. (The links will take you to the jQueryUI site, where there are live examples.)

Accordion

accordionTabs

tabsBy structuring your markup in a specific way, you can make simple calls to jQueryUI to re-shape what you’ve rendered on the page into these cool user interface elements. Using a Data View Web Part (DVWP), you can pull the labels for the sections and content in the accordion or the tabs names and content from lists. All it takes is emitting some well-structured markup in your XSL.

Here are Carlos’ examples:

Accordion

<xsl:template name="dvt_1">
  <xsl:variable name="dvt_StyleName">Table</xsl:variable>
  <xsl:variable name="Rows" select="/dsQueryResponse/Rows/Row"/>
  <xsl:variable name="dvt_RowCount" select="count($Rows)" />
  <xsl:variable name="dvt_IsEmpty" select="$dvt_RowCount = 0" />
  <xsl:choose>
    <xsl:when test="$dvt_IsEmpty">
      <xsl:call-template name="dvt_1.empty" />
    </xsl:when>
    <xsl:otherwise>
        <div id="accordion">
          <xsl:call-template name="accordionMarkup">
            <xsl:with-param name="Rows" select="$Rows" />
          </xsl:call-template>
        </div>
    </xsl:otherwise>
  </xsl:choose>
</xsl:template>

<xsl:template name="accordionMarkup">
  <xsl:param name="Rows" />
  <xsl:for-each select="$Rows">
    <h3>
      <a href="#">
        <xsl:value-of select="@Title" />
      </a>
    </h3>
    <div>
      <xsl:value-of select="@panelText" disable-output-escaping="yes" />
    </div>
  </xsl:for-each>
</xsl:template>

<xsl:template name="dvt_1.empty">
  <xsl:variable name="dvt_ViewEmptyText">No items.</xsl:variable>
  <table border="0" width="100%">
    <tr>
      <td class="ms-vb">
        <xsl:value-of select="$dvt_ViewEmptyText" />
      </td>
    </tr>
  </table>
</xsl:template>

Tabs

<xsl:template name="dvt_1">
  <xsl:variable name="dvt_StyleName">Table</xsl:variable>
  <xsl:variable name="Rows" select="/dsQueryResponse/Rows/Row"/>
  <xsl:variable name="dvt_RowCount" select="count($Rows)" />
  <xsl:variable name="dvt_IsEmpty" select="$dvt_RowCount = 0" />
  <xsl:choose>
    <xsl:when test="$dvt_IsEmpty">
      <xsl:call-template name="dvt_1.empty" />
    </xsl:when>
    <xsl:otherwise>
        <div id="tabs">
          <xsl:call-template name="tabsList">
            <xsl:with-param name="Rows" select="$Rows" />
          </xsl:call-template>
          <xsl:call-template name="tabsPanels">
            <xsl:with-param name="Rows" select="$Rows" />
          </xsl:call-template>
        </div>
    </xsl:otherwise>
  </xsl:choose>
</xsl:template>

<xsl:template name="tabsList">
  <xsl:param name="Rows" />
  <ul>
    <xsl:for-each select="$Rows">
      <li><a href="{concat('#tabs-',@ID)}"><xsl:value-of select="@Title" /></a></li>
    </xsl:for-each>
  </ul>
</xsl:template>

<xsl:template name="tabsPanels">
  <xsl:param name="Rows" />
  <xsl:for-each select="$Rows">
    <div id="{concat('tabs-',@ID)}">
      <xsl:value-of select="@panelText" disable-output-escaping="yes" />
    </div>
  </xsl:for-each>
</xsl:template>

<xsl:template name="dvt_1.empty">
  <xsl:variable name="dvt_ViewEmptyText">No items.</xsl:variable>
  <table border="0" width="100%">
    <tr>
      <td class="ms-vb">
        <xsl:value-of select="$dvt_ViewEmptyText" />
      </td>
    </tr>
  </table>
</xsl:template>

One of the nice things about jQueryUI is that using the basic functionality once you have the markup in place requires very little script.

For an accordion:

$(document).ready(function(){
  $("#accordion").accordion();
});

For tabs:

$(document).ready(function(){
  $("#tabs").tabs();
});

There are various options for both functions which you can read about on the jQueryUI site, but the simple script above gets you the default functionality. Obviously, you’d need to reference the jQuery and jQueryUI files and link to the jQueryUI css, but if you’ve used jQueryUI, or even just jQuery, you are probably familiar with how to do that.

Thanks, Carlos!

7 Comments

  1. Hi Marc,

    I’ am getting xslt errors trying to point to jQuery link in XSL. I’ am trying it in BDC List WP.

    Could you kindly share the piece where you provided jQuery reference?

    Thanks.

    Reply
  2. Just thought of something else to mention. If you’re going to have multiple accordion or tab controls on a page, you’re either going to have to call the widget code for each unique ID, or you’re going to have to call it for a class and modify the XSL so that class name is there.

    So where it says: or you’d use instead or

    Your jQuery would then be either $(".accordion").accordion(); or $(".tabs").tabs();

    Reply
    • Can you provide an example of how the code would for the two different DataViews that would appear on the same page? I have the situation where I need to display different data in the same page using the accordion for both. Thank you.

      Reply
  3. My headers are repeating and include the same content over and over. For example: I have a group ‘Red’ and a group ‘Green’. It will display the accordion headers as Green (with content); Red (with content); Green (with content) and continue to repeat. How do I make the headers only appear once in the accordion?

    Reply

Have a thought or opinion?