How to Add a Tab to the Ribbon in SharePoint Foundation



(Before he left for a week of laying on various tropical beaches with drinks in his hand, Dallas asked me to post this for him. Since I’m stuck in the rainy Northwest and had nothing better to do, I was happy to oblige him.) 


The ribbon has unified the command surface inside of SharePoint. It is now the primary point of entry for working with items inside of SharePoint. As such the ribbon is extensible through the use of declarative XML in a Feature.


This post will cover how to add a new tab to the ribbon in Microsoft SharePoint Foundation 2010. It will also, by necessity, cover how to create a group, controls, template, and scaling behavior. I will build this solution in Visual Studio 2010 Beta 2 and as a sandboxed solution for the ease of deployment.


The following will appear in a future version of the SDK. It is preliminary documentation and subject to change.


First, you will want to create a new project. Click on File, New, and then Project.


Under Visual C#, choose Empty SharePoint Project and enter AddARibbonTab for the Name. Click OK.


In the SharePoint Customization Wizard, choose Deploy as a sandboxed solution. Click Finish.


In the Solution Explorer, right click on Features and choose Add Feature.


Change the Title of the Feature to Custom Ribbon Tab. Also, rename Feature1 in the Solution Explorer to CustomRibbonTab.


Right click on the AddARibbonTab project in the Solution Explorer and choose Add, New Item…


In the Add New Item dialog, choose the Empty Element template. Enter CustomRibbonTab as the Name.


In the Elements.xml file, insert the following CustomAction element. The Location attribute tells the CustomAction where to apply the customization. The following list explains the acceptable values.






















Value


Description


CommandUI.Ribbon


Customization appears everywhere for the specified RegistrationId.


CommandUI.Ribbon.ListView


Customization appears when the list view Web Part is present.


CommandUI.Ribbon.EditForm


Customization appears on the edit form.


CommandUI.Ribbon.NewForm


Customization appears on the new form.


CommandUI.Ribbon.DisplayForm


Customization appears on the display form.


 


<?xml version=1.0 encoding=utf-8?>


<Elements xmlns=http://schemas.microsoft.com/sharepoint/>


  <CustomAction


    Id=MyCustomRibbonTab


    Location=CommandUI.Ribbon.ListView


    RegistrationId=101


    RegistrationType=List>


 


  </CustomAction>


</Elements>


 


Add the following elements to define the ribbon extension and tab. The Location on the CommandUIDefinition element defines where the controls inside of it will render. In this example, you reference the Tabs collection of the ribbon. The _children convention tells the ribbon to insert the following XML, whether it is a tab, group, or control, into the collection of tabs. The Sequence attribute on the Tab element defines where the tab will render in regards to other tabs. The default tabs use multiples of 100, so the Sequence attribute should not be a multiple of 100 to prevent collisions.


<CommandUIExtension>


      <CommandUIDefinitions>


        <CommandUIDefinition


          Location=Ribbon.Tabs._children>


          <Tab


            Id=Ribbon.CustomTabExample


            Title=My Custom Tab


            Description=This holds my custom commands!


            Sequence=501>


 


When creating a custom tab, you must define how the tab will scale when controls are added. This is handled through the use of the Scaling element along with a GroupTemplate. The MaxSize element defines the maximum size of the controls in the group. The Scale element defines how the group will scale in different situations. The GroupId attribute associates a group with the scale size. The Size attribute is defined by the Layout element, which is defined later in this topic.


            <Scaling


              Id=Ribbon.CustomTabExample.Scaling>


              <MaxSize


                Id=Ribbon.CustomTabExample.MaxSize


                GroupId=Ribbon.CustomTabExample.CustomGroupExample


                Size=OneLargeTwoMedium/>


              <Scale


                Id=Ribbon.CustomTabExample.Scaling.CustomTabScaling


                GroupId=Ribbon.CustomTabExample.CustomGroupExample


                Size=OneLargeTwoMedium />


            </Scaling>


 


Now, you will define the groups of controls that will appear on the tab. The Group element contains the usual attributes along with a Template attribute. The Template attribute references the GroupTemplate that is defined later in this topic. The Controls element contains the controls that will render in the group. These can be buttons, dropdowns, and other control types. You can find a list in the SDK at this address: http://msdn.microsoft.com/en-us/library/ee537017(office.14).aspx. The controls inside the group must define the TemplateAlias and Command attributes. Like tabs, each control has a Sequence attribute that defines where they will render in the group. The default controls are based on multiples of 10, so any custom controls should not use a multiple of 10 to avoid collisions. The Command attribute is used by the CommandUIHandler defined later in this topic but is required even if the CommandUIHandler is not specified. The TemplateAlias attribute defines where the control will render in relationship to the GroupTemplate.


            <Groups Id=Ribbon.CustomTabExample.Groups>


              <Group


                Id=Ribbon.CustomTabExample.CustomGroupExample


                Description=This is a custom group!


                Title=Custom Group


                Sequence=52


                Template=Ribbon.Templates.CustomTemplateExample>


                <Controls Id=Ribbon.CustomTabExample.CustomGroupExample.Controls>


                  <Button


                    Id=Ribbon.CustomTabExample.CustomGroupExample.HelloWorld


                    Command=CustomTabExample.HelloWorldCommand


                    Sequence=15


                    Description=Says Hello to the World!


                    LabelText=Hello, World!


                    TemplateAlias=cust1/>


                  <Button


                    Id=Ribbon.CustomTabExample.CustomGroupExample.GoodbyeWorld


                    Command=CustomTabExample.GoodbyeWorldCommand


                    Sequence=17


                    Description=Says Good-bye to the World!


                    LabelText=Good-bye, World!


                    TemplateAlias=cust2/>


                  <Button


                    Id=Ribbon.CustomTabExample.CustomGroupExample.LoveWorld


                    Command=CustomTabExample.LoveWorldCommand


                    Sequence=19


                    Description=Says I &lt;3 the World!


                    LabelText=I &lt;3 you, World!


                    TemplateAlias=cust3/>


                </Controls>


              </Group>


            </Groups>


          </Tab>


        </CommandUIDefinition>


 


With that code in place, you have finished the first CommandUIDefinition that includes the tab, groups, and controls. You need to define how the controls will render inside of the group. You do this using a GroupTemplate element in another CommandUIDefinition. The CommandUIDefinition will have a Location of Ribbon.Templates._children. This follows the pattern for Groups and Tabs.


The GroupTemplate element contains a Layout element with Section and Row elements. The Layout element has a LayoutTitle that is used for the Size attribute on the MaxSize and Scale elements. The Section elements define the position of the controls as well as how many rows will render inside that section. The Row element contains one or more ControlRef elements. ControlRef elements define how your controls will display. The DisplayMode attribute can have the following values:



















Value


Description


Small


Renders as a small icon without label text.


Medium


Renders as a 16×16 icon with label text.


Large


Renders as a 32×32 icon with label text.


Text


Renders as text only.


 


The ControlRef elements also define the TemplateAlias values that you used for the TemplateAlias attribute on the buttons. Note that only one control per group can use this value. You cannot have two controls with the same TemplateAlias unless it is an OverflowArea. You can reuse the TemplateAlias across different groups though. There is also an OverflowArea element that defines how controls will render if there are too many controls in a group. The TemplateAlias attributes that refer to OverflowAreas in the GroupTemplate can be used on multiple controls.


In this example, you will define two sections for rendering the controls. One section will be a row of large buttons while the other section will contain two rows of medium-sized buttons.


        <CommandUIDefinition Location=Ribbon.Templates._children>


          <GroupTemplate Id=Ribbon.Templates.CustomTemplateExample>


            <Layout


              Title=OneLargeTwoMedium


              LayoutTitle=OneLargeTwoMedium>


              <Section Alignment=Top Type=OneRow>


                <Row>


                  <ControlRef DisplayMode=Large TemplateAlias=cust1 />


                </Row>


              </Section>


              <Section Alignment=Top Type=TwoRow>


                <Row>


                  <ControlRef DisplayMode=Medium TemplateAlias=cust2 />


                </Row>


                <Row>


                  <ControlRef DisplayMode=Medium TemplateAlias=cust3 />


                </Row>


              </Section>


            </Layout>


          </GroupTemplate>


        </CommandUIDefinition>


      </CommandUIDefinitions>


 


The final step is to write handlers for the buttons. These are inside CommandUIHandler elements. The Command attribute is a unique name for the command and used for the Command attribute on controls. The CommandAction attribute contains the action that is performed for the control. This can be JavaScript, an URL, or anything that was previously contained in an UrlAction element.


      <CommandUIHandlers>


        <CommandUIHandler


          Command=CustomTabExample.HelloWorldCommand


          CommandAction=javascript:alert(‘Hello, world!’); />


        <CommandUIHandler


          Command=CustomTabExample.GoodbyeWorldCommand


          CommandAction=javascript:alert(‘Good-bye, world!’); />


        <CommandUIHandler


          Command=CustomTabExample.LoveWorldCommand


          CommandAction=javascript:alert(‘I love you, world!’); />


      </CommandUIHandlers>


    </CommandUIExtension>


 


With the addition of the CommandUIHandlers, you have finished your Elements.xml file. Press F5 to deploy your solution. Then, navigate to the Shared Documents folder. You should see the Custom Tab. Click on Custom Tab to open it. Click any of the buttons to show the associated alert.


Hopefully this walkthrough has been helpful! If you have any questions or concerns, please let me know in the comments.


 


Full Code Listing:


<?xml version=1.0 encoding=utf-8?>


<Elements xmlns=http://schemas.microsoft.com/sharepoint/>


  <CustomAction


    Id=MyCustomRibbonTab


    Location=CommandUI.Ribbon.ListView


    RegistrationId=101


    RegistrationType=List>


      <CommandUIExtension>


        <CommandUIDefinitions>


          <CommandUIDefinition


            Location=Ribbon.Tabs._children>


            <Tab


              Id=Ribbon.CustomTabExample


              Title=My Custom Tab


              Description=This holds my custom commands!


              Sequence=501>


            <Scaling


              Id=Ribbon.CustomTabExample.Scaling>


              <MaxSize


                Id=Ribbon.CustomTabExample.MaxSize


                GroupId=Ribbon.CustomTabExample.CustomGroupExample


                Size=OneLargeTwoMedium/>


              <Scale


                Id=Ribbon.CustomTabExample.Scaling.CustomTabScaling


                GroupId=Ribbon.CustomTabExample.CustomGroupExample


                Size=OneLargeTwoMedium />


            </Scaling>


            <Groups Id=Ribbon.CustomTabExample.Groups>


              <Group


                Id=Ribbon.CustomTabExample.CustomGroupExample


                Description=This is a custom group!


                Title=Custom Group


                Sequence=52


                Template=Ribbon.Templates.CustomTemplateExample>


                <Controls Id=Ribbon.CustomTabExample.CustomGroupExample.Controls>


                  <Button


                    Id=Ribbon.CustomTabExample.CustomGroupExample.HelloWorld


                    Command=CustomTabExample.HelloWorldCommand


                    Sequence=15


                    Description=Says hello to the World!


                    LabelText=Hello, World!


                    TemplateAlias=cust1/>


                  <Button


                    Id=Ribbon.CustomTabExample.CustomGroupExample.GoodbyeWorld


                    Command=CustomTabExample.GoodbyeWorldCommand


                    Sequence=17


                    Description=Says good-bye to the World!


                    LabelText=Good-bye, World!


                    TemplateAlias=cust2/>


                  <Button


                    Id=Ribbon.CustomTabExample.CustomGroupExample.LoveWorld


                    Command=CustomTabExample.LoveWorldCommand


                    Sequence=19


                    Description=Says I love the World!


                    LabelText=I love you, World!


                    TemplateAlias=cust3/>


                </Controls>


              </Group>


            </Groups>


          </Tab>


        </CommandUIDefinition>


        <CommandUIDefinition Location=Ribbon.Templates._children>


          <GroupTemplate Id=Ribbon.Templates.CustomTemplateExample>


            <Layout


              Title=OneLargeTwoMedium


              LayoutTitle=OneLargeTwoMedium>


              <Section Alignment=Top Type=OneRow>


                <Row>


                  <ControlRef DisplayMode=Large TemplateAlias=cust1 />


                </Row>


              </Section>


              <Section Alignment=Top Type=TwoRow>


                <Row>


                  <ControlRef DisplayMode=Medium TemplateAlias=cust2 />


                </Row>


                <Row>


                  <ControlRef DisplayMode=Medium TemplateAlias=cust3 />


                </Row>


              </Section>


            </Layout>


          </GroupTemplate>


        </CommandUIDefinition>


      </CommandUIDefinitions>


      <CommandUIHandlers>


        <CommandUIHandler


          Command=CustomTabExample.HelloWorldCommand


          CommandAction=javascript:alert(‘Hello, world!’); />


        <CommandUIHandler


          Command=CustomTabExample.GoodbyeWorldCommand


          CommandAction=javascript:alert(‘Good-bye, world!’); />


        <CommandUIHandler


          Command=CustomTabExample.LoveWorldCommand


          CommandAction=javascript:alert(‘I love you, world!’); />


      </CommandUIHandlers>


    </CommandUIExtension>


  </CustomAction>


</Elements>


 

Comments (13)

  1. Deepak Kejriwal says:

    Hi,

       Thanks for posting this blog. Actully i am facing one problem. I want to add a new button called "Save and New" in Ribbon.ListForm.Edit.Commit group of list new form. I am able to add the button but the problem is it get disabled after mouse click. Here is XML entry for it :-

    <CustomAction Id="Ribbon.ListForm.Edit.Commit.AddAButton"  Location="CommandUI.Ribbon.NewForm"  RegistrationId="10001"  RegistrationType="List" >

       <CommandUIExtension>

         <CommandUIDefinitions>

           <CommandUIDefinition Location="Ribbon.ListForm.Edit.Commit.Controls._children">

             <Button Id="Ribbon.ListForm.Edit.Commit.NewRibbonButton"

                     Command="NewRibbonButtonCommand"

                     Image32by32="/_layouts/1033/images/formatmap32x32.png?vk=4536"

                     Image32by32Left="-64" ToolTipTitle="This Tool Tip title" ToolTipDescription="This Tool Tip Descript"

                     Image32by32Top="-160"

                     LabelText="Save And New"

                     TemplateAlias="o1" />

           </CommandUIDefinition>

         </CommandUIDefinitions>

         <CommandUIHandlers>

           <CommandUIHandler Command="NewRibbonButtonCommand" CommandAction ="javascript:SaveAndNewOnclick();" />

         </CommandUIHandlers>

       </CommandUIExtension>

     </CustomAction>

    Please help me for this.

  2. yaroslavp says:

    Excellent article – really sheds some light on ribbon dev. I noticed CommandUIHandler has a way to define javascript command action – is there a way to do action handling within .NET assembly or not?

  3. dushes says:

    Hello Yaroslav,

    yes, there is a way to register handle commands of the server side. Please check out the http://www.projectserver2010blog.com/2010/01/sharepoint-2010-ribbon-customization_06.html post.

  4. Dima Shelemov says:

    Very usefull documentation for ribbon development. I try to create tab for my custom webpart.

    <?xml version="1.0" encoding="utf-8"?>

    <Elements xmlns="http://schemas.microsoft.com/sharepoint/"&gt;

     <CustomAction

       Id="MyCustomRibbonTab"

       Location="CommandUI.Ribbon">

    …all from post example

     </CustomAction>

    </Elements>

    And in code of webpart class

    protected override void OnLoad(EventArgs e)

    {

    SPRibbon current = SPRibbon.GetCurrent(this.Page);

    if (current != null)

    {

    if (!current.IsTabAvailable("MyCustomRibbonTab"))

    current.MakeTabAvailable("MyCustomRibbonTab");

    }

    base.OnLoad(e);

    }

    but receive an exception on client when select my tab

    You must set the GroupMaxSize of Group: Ribbon.CustomTabExample.CustomGroupExample before you add ScalingSteps for it

    The response from server the order of Scaling children are broken. First comes the element Scale and second MaxSize. How can i set the order of elements in Scaling (Sequence don’t help)?

  5. Dima,

    Make sure that you have <MaxSize> before <Scale> as shown in the example. The order is controlled simply by where they appear in the XML. This error occurs if you put the <Scale> element before the <MaxSize> element. The error can also occur if two elements have the same Id attribute. Make sure you haven’t deployed a customization with the same Id.

    Hope this helps,

    Dallas

  6. Dima Shelemov says:

    Hello, Dallas!

    I check my code and xml definition for same Ids. All id’s differs.

    Here is my little example to reproduce the problem. http://rapidshare.com/files/338667098/VisualWebPartUpdatePanel.wsp.html

    Please check the problem.

    Thank you for a quick reply.

    Dima

  7. dmcweeney says:

    Do you have to define a GroupTemplate for a custom tab or is it possible to refer/reuse the group templates defined by cmdui.xml? If so how?

    Thanks

    Donal

  8. Dima,

    I tried to download but RapidShare says that it has reached the limit. Can you e-mail it to me? dallast at microsoft.com.

    Donal,

    For a custom tab, you have to define the GroupTemplate. For a custom group, you can reuse the templates defined in CMDUI.xml.

    Thanks,

    Dallas

  9. Dima Shelemov says:

    Hello, Dallas!

    I didn’t find e-mail in your profile. Maybe through sky drive you can receive example http://cid-f7b668eec5ab0647.skydrive.live.com/self.aspx/.Public/VisualWebPartUpdatePanel.wsp

    Thanks,

    Dima

  10. Syntax says:

    Hi,

    i have a problem about ribbon.. i was show new custom tab in my custom application page but not working Command actions.. what would you recommend for custom tab in the custom aspx page (in /layouts)

    my custom ribbon don’t running in list or webpart page, my application running in the layouts 🙁

    i’m use this code for show ribbon tab:

    var ribbon = SPRibbon.GetCurrent(Page);

                if (ribbon != null) {

                    ribbon.Minimized = false;

                    ribbon.CommandUIVisible = true;

                    const string initialTabId = "UserDataRibbon";

                    if (!ribbon.IsTabAvailable(initialTabId))

                        ribbon.MakeTabAvailable(initialTabId);

                    ribbon.InitialTabId = initialTabId;

               }

    my element xml:

    <CustomAction Id="MyCustomTabId" Location="CommandUI.Ribbon">

       <CommandUIExtension>

         <CommandUIDefinitions>

           <CommandUIDefinition Location="Ribbon.Tabs._children">

             <Tab

               Id="MyCustomTab"

               Title="Custom Tab"

               Description="…"

               Sequence="501">

               <Scaling Id="Ribbon.MyCustomTab.Scaling">

                 <MaxSize  Id="Ribbon.MyCustomTab.NewMaxSize" GroupId="Ribbon.MyCustomTab.NewGRP" Size="OneLargeTMPL"/>

                 <MaxSize  Id="Ribbon.MyCustomTab.EditMaxSize" GroupId="Ribbon.MyCustomTab.EditGRP" Size="TwoRowMediumTMPL"/>

                 <MaxSize  Id="Ribbon.MyCustomTab.DataMaxSize" GroupId="Ribbon.MyCustomTab.DataGRP" Size="TwoLargeTMPL"/>

                 <Scale Id="Ribbon.MyCustomTab.Scaling.NewScaling" GroupId="Ribbon.MyCustomTab.NewGRP" Size="OneLargeTMPL" />

                 <Scale Id="Ribbon.MyCustomTab.Scaling.EditScaling" GroupId="Ribbon.MyCustomTab.EditGRP" Size="TwoRowMediumTMPL" />

                 <Scale Id="Ribbon.MyCustomTab.Scaling.DataScaling" GroupId="Ribbon.MyCustomTab.DataGRP" Size="TwoLargeTMPL" />

               </Scaling>

               <Groups Id="Ribbon.MyCustomTab.Groups">

                 <Group

                   Id="Ribbon.MyCustomTab.NewGRP"

                   Description="New Item Command"

                   Title="New"

                   Sequence="52"

                   Template="Ribbon.Templates.OneLargeTMPL">

                   <Controls Id="Ribbon.MyCustomTab.NewGRP.Controls">

                     <Button

                       Id="Ribbon.MyCustomTab.NewGRP.NewItem"

                       Command="Custom.Command.NewItem"

                       Description="Add New Entry"

                       Sequence="15"

                       LabelText="New"

                       TemplateAlias="c1"/>

                   </Controls>

                 </Group>

                 <Group

                   Id="Ribbon.MyCustomTab.EditGRP"

                   Description="Edit Item Commands"

                   Title="Edit"

                   Sequence="62"

                   Template="Ribbon.Templates.TwoRowMediumTMPL">

                   <Controls Id="Ribbon.MyCustomTab.EditGRP.Controls">

                     <Button

                       Id="Ribbon.MyCustomTab.EditGRP.EditEntry"

                       Command="Custom.Command.EditEntry"

                       Description="Edit Entry"

                       LabelText="Edit Entry"

                       TemplateAlias="c1"/>

                     <Button

                       Id="Ribbon.MyCustomTab.EditGRP.DeleteEntry"

                       Description="Remove Entry"

                       LabelText="Remove Entry"

                       TemplateAlias="c2"/>

                   </Controls>

                 </Group>

                 <Group

                   Id="Ribbon.MyCustomTab.DataGRP"

                   Description="Data Management"

                   Title="Import/Export"

                   Sequence="72"

                   Template="Ribbon.Templates.TwoLargeTMPL">

                   <Controls Id="Ribbon.MyCustomTab.DataGRP.Controls">

                     <Button

                       Id="Ribbon.MyCustomTab.DataGRP.ImportData"

                       Description="Import"

                       LabelText="Import"

                       TemplateAlias="c1"/>

                     <Button

                       Id="Ribbon.MyCustomTab.DataGRP.ExportData"

                       Command="Custom.Command.ExportData"

                       Description="Export"

                       LabelText="Export"

                       TemplateAlias="c2"/>

                   </Controls>

                 </Group>

               </Groups>

             </Tab>

           </CommandUIDefinition>

         </CommandUIDefinitions>

         <CommandUIHandlers>

           <CommandUIHandler

             Command="Custom.Command.NewItem"

             CommandAction="javascript:alert(‘Hello’);" EnabledScript="true" />

           <CommandUIHandler

             Command="Custom.Command.EditEntry"

             CommandAction="javascript:alert(‘Hello’);" EnabledScript="true" />

         </CommandUIHandlers>

       </CommandUIExtension>

     </CustomAction>

    what do I need to running correctly?

    thanks a lot..

  11. rvaniren says:

    Hi all,

    Thanks for this post! Unfortunately i was’nt able to get the custom tab into the ribbon. I have tried several examples, but none of them is working.. I am probably doing something wrong, could anyone help me out? I’ve done everything above, created a new sharepoint project, put in an empty element, copied the code and deployed it, but no results at all.

    Does anyone have the same problem or does anyone know what I do wrong? Thanks in advance!

  12. Scotchy2 says:

    If you are getting the error "You must set the GroupMaxSize of Group: Ribbon.CustomTabExample.CustomGroupExample before you add ScalingSteps for it" when clicking on the tab you must change add sequence to MaxSize and Scale.  Then change the GUID on the feature so that these changes are picked up.

    <MaxSize Sequence="1" …

    <Scale Sequence="2" …

  13. Senthil K says:

    Hi Scotchy2,

    You are a genius. Saved my day trying to find a solution for the ussue "You must set the GroupMaxSize of Group". After 2 days of searching did not find that we should use sequence to overcome this. Thanks a ton.

    Thanks a lot,

    Senthil