Some good posts are starting to appear on SharePoint 2010 ribbon customization now, and over the next couple of articles I want to cover some key things you might want to do with the ribbon when developing your solutions. Broadly speaking, the plan for this series is:
- Creating tabs, groups and controls (this post)
- Adding items into existing ribbon tabs and groups
- Working with the ribbon programatically e.g. from web parts and field controls
Diving straight in then, some ribbon fundamentals:
- Ribbon elements must be defined in declarative XML with the CustomAction tag – even if you will actually use code to manipulate them (e.g. make visible, enable/disable etc.)
- The “control hierarchy” is ribbon > tab > group > controls – we’ll explore all these in this post
- Individual buttons/controls do not appear and disappear on the ribbon. This is a key ribbon principle, to avoid the “I’m sure this button was here yesterday!” effect – instead, depending on the context:
- Entire tabs can be shown/hidden
- Individual controls can be enabled/disabled
- It’s not possible to add custom controls to the ribbon e.g. a custom .ascx/server control. The list of controls defined by the ribbon can be found here in the MSDN docs, and includes things like Button, Checkbox, Color Picker, Combo Box, Dropdown, Textbox, Toggle Button etc, but also some funky ones like Spinner, Split Button and Flyout Anchor (definitions of these exotic varieties can be found in the documentation). Flyout Anchor is particularly interesting as it takes XML as a datasource and can be used to build interesting “pickers” e.g. with images – I’ll hopefully cover this in detail in a future post
- The definitions for the out-of-the-box ribbon elements are split across several files in the SharePoint root, with TEMPLATE\GLOBAL\XML\CMDUI.XML being the main one. You will likely spend significant time in this file looking for examples similar to what you’re building.
- By embedding it into your declarative XML (via a separate CustomAction with a new ‘Location=”ScriptLink”’ attribute) – this post uses this approach, though later in the series I’ll show the next option
Example – creating a new custom tab
This is a fairly in-depth example, since by necessity it also covers creating custom groups and controls too. Also, to kill two birds with one stone, I thought it would be good to look at the new ‘notifications’ and ‘status’ frameworks in the Client Object Model for passing messages back to the user in your SharePoint app. First we’ll walk through what my custom tab looks like, then what it actually does. I have a tab titled “Chris’s custom tab” with 3 groups (“Notification messages”, “Add status messages” and “Remove status messages”) each with some buttons of different sizes and images in them:
Clicking the ‘Notify hello’ button adds a transient message in the notifications area (fades in from right and stays for 5 seconds by default):
Clicking the ‘Info status’ button shows a status message this time, in the default color (this remains on screen until removed with another API call):
Clicking the ‘Warning status’ button shows a status message of a different color to indicate severity, I chose red:
You might also have noticed the ‘remove status’ buttons have become enabled when a status message is present – such client-side checks can be done by linking a ‘CommandUIHandler’ with an ‘EnabledScript’ attribute, as we’re about to see.
So what XML is required to get that? Well before you scroll through, note that I’ve taken the complex route with some of the declarations so that my example is as informative as possible – most samples I’ve seen so far simply add a button or two in a single group and don’t specify the “’group template” details which determines how the controls in the group get laid out. This is fine for a button or two as you can just reference an out-of-the-box group template, but if you want to do anything different you’re a bit stuck so hopefully this is good documentation:
Some key points, following the XML sequence:
- The Location attribute of CustomAction for ribbon elements should always be “CommandUI.Ribbon”
- The Location attribute of CustomAction for script is a new value, “ScriptLink”
- My ribbon tab is scoped to document libraries only – this is courtesy of the RegistrationType=”List” RegistrationId=”101″ attributes (which is exactly what you did when targeting a CustomAction to doc libs in SharePoint 2007, no change there)
- When targeting a list in this way, RegistrationId refers to the list template ID (e.g. generic list = 100. document library = 101 etc. – here’s a full list of list template IDs for 2007, there could be a couple of new ones in 2010) – it is not possible to declaratively target a list by e.g. GUID or URL. So consider that this could drive you to create a list template when you otherwise might not have.
- Other options for the RegistrationType continue to be “ContentType”, “ProgID” and “FileType”, but I’m pretty sure only “List” can be used for ribbon elements, but I’ve not tested that yet so I reserve the right to be wrong! If you want a different scope level, you would omit the RegistrationType and RegistrationId attributes and use code such as SPRibbon.MakeTabAvailable() to conditionally show the ribbon. More on this later in the series when I show how to add ribbon customizations for a web part or custom field control.
- Another element you might have multiple of – one for the main customization definition, one for each of the “GroupTemplate” elements being provisioned (more on this later). For the main one, the “Location” attribute here is crucially important as this specifies where the customization should appear. My value of “Ribbon.Tabs._children” indicates I’m adding something into the “Ribbon.Tabs” collection defined by SharePoint (typically in CMDUI.XML) – “_children” is a convention used when adding to many collections in the ribbon architecture. We’ll look at how to add new groups and controls into an existing group in the next article, but as a quick example, adding a group into “Ribbon.Library.Groups._children” would make your group appear somewhere in here (depending on the “Sequence” value assigned on the definition for the group):
- The “Sequence” attribute decides where to place my tab amongst the existing ones. Out-of-the-box values are generally multiples of 10, sometimes of 5, so your sequence values should avoid such numbers to avoid conflict. Generally you’ll need to find the declaration of the surrounding elements near where you are targeting (in CMDUI.XML) to find the appropriate number.
- Scaling (and children):
- This section defines how your elements should behave when the window is resized and there’s not enough room. You need a “MaxSize” and “Scale” element for each Group you define. These define the size and layout the element(s) should be at when at “max”, and also what to change to when the window is smaller – effectively you can provide multiple layouts for your controls depending on the window size (e.g. prioritising the important buttons).
- This is the “section on the ribbon tab” which is the container for your controls – in the small image above, an example of a Group is ‘View Format’ which contains the two leftmost buttons. Key things here are the “Sequence” (same deal as elsewhere) and the “Template” – this is a reference to a “GroupTemplate” element (which we’ll come onto shortly). In essence, this is the link which will tell the ribbon framework how to lay out the controls in this group.
- Fairly obvious, this is the parent node for any controls you want to add e.g. buttons, dropdowns etc etc. Note that each of your controls in here must have a “TemplateAlias” attribute – this tells the framework exactly where to place the individual control within the GroupTemplate which is referenced.
- Similar to defining say, a HTML table, this section provides the actual layout of the controls, alignments, control sizes etc. Each control which is being declared needs a corresponding “ControlRef” element which will be matched to the control on the “TemplateAlias” value.