Share via


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="https://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: https://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 16x16 icon with label text.

Large

Renders as a 32x32 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="https://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

  • Anonymous
    December 08, 2009
    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.

  • Anonymous
    December 21, 2009
    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?

  • Anonymous
    January 07, 2010
    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.

  • Anonymous
    January 19, 2010
    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/">  <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)?

  • Anonymous
    January 20, 2010
    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

  • Anonymous
    January 20, 2010
    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

  • Anonymous
    January 20, 2010
    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

  • Anonymous
    January 21, 2010
    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

  • Anonymous
    January 21, 2010
    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

  • Anonymous
    February 18, 2010
    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..

  • Anonymous
    March 09, 2010
    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!

  • Anonymous
    September 30, 2010
    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" ...

  • Anonymous
    April 21, 2014
    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