6 UI API - Reference Documentation
Authors: Marc Palmer (marc@grailsrocks.com)
Version: 1.0.RC2
Table of Contents
6 UI API
The UI API provides a set of tags for common UI elements, without tieing an application to any specific CSS or JavaScript library.The UI tags have implementations that come from a "UI Set" which is a convention-based collection of GSP templates.This semantic identification of UI elements provides a level of abstraction from their actual HTML rendering. While HTML5 is a major step forward, we are still in a situation where UI elements are often built out of multiple markup tags which vary between CSS and JS frameworks. For this reason, we cannot have UI tags that render the actual HTML in a fixed way, if we want our UIs - especially those from plugins - to work with different UI frameworks.This allows plugins to provide high quality UI to your application, without relying on you to integrate the plugin views with your look and feel.It is very important to understand that using these tags does not tie you to any UI library or specific look and feel. That is entirely down to the UI Set that your application/theme uses, and can be switched at runtime.You no longer have to write your HTML markup to match specific CSS frameworks you are using. Use the UI tags and you can pair this with your own UI Set, or use an off the shelf one and leverage the theme system to get polished off-the-shelf UIs - or create your own themes to allow your users a choice of look and feel.There are tags for rendering the following content elements
- fields (including label, errors, hint and structural markup)
- buttons
- tabs
- navigation
- carousels
- tables
- pagination
- images
- messages
- headings
- logos
- avatars
6.1 About UI Sets
UI Sets provide the implementation of the UI tags, and the named UI Set in effect can be set at runtime.This is typically automatically selected by the Theme currently in use, but you do not have to use themes to use UI Sets.A UI Set implementation is just a named collection of GSP templates in a convention-based path in a plugin or application.Why do we need this?
Even with increasing adoption of HTML5, the truth is that there are still many ways to render the markup for even the relatively small subset of UI elements that the Platform UI API supports.Therefore this level of abstraction is required to make Themes work, so that the functionally equivalent visual and input elements can be rendered with completely different structural markup and styling.Take form fields as an example. These can generally be decomposed into the following components:- A label
- An input widget of some sort, either standard HTML or some custom JavaScript based widget
- A field hint and/or field error message
<label for="firstName" class="control-label">First Name</label> <div class="controls"> <input name="firstName" value=""/> <span class="help-block">Your first name</span> </div>Fine. However if you then switch to another CSS framework, you will often find that this no longer renders anything like the way you wanted because there is no standard structural UI layout and styling mechanism in HTML. Specifically:# The structural markup will often be different. One designer might use nested divs to lay out the label, field and hint. Another may use a single div or no div at all for the components, another may rely on the order of sibling elements
- The CSS class names for the structural markup will usually be different
- The CSS class names for the label, widget and hint/error will often be different
<ui:field name="x"/>
and work with existing and future CSS frameworks without modification to the GSP view - which after all only wanted to render a field.This is how plugins can expose UI that fits in with the application's chosen theme.The secret to making your UI work with theming is relinquishing control over the details of HTML markup and CSS classes.That is, unless you are also the author of the theme you are using - in which case you still have full control.
6.2 The UI Elements
Any application or plugin can use the UI element tags.The following sections show examples of the various tags being used. See the reference for each tag for full details.6.2.1 Widgets
The UI API provides support for a range of widgets for plugins and applications to use.For full details see the tag reference section.Button
The button tag renders a button with options for:- the kind of rendering (input with type submit, button tag, or anchor)
- resolving the text via i18n messages
- different "modes" that give cues to the user to indicate e.g. primary buttons
<ui:button mode="primary">OK</ui:button> <ui:button>Save</ui:button> <ui:button enabled="false">Cancel</ui:button> <ui:button mode="primary" text="button.ok"/> <ui:button kind="anchor" href="#" mode="cancel" text="button.cancel"/> <ui:button kind="submit" mode="primary" text="Send"/>
Field
The field tag lets you specify a field that must be rendered - usually within a form.The UI Set is responsible for all structural markup relating to this field, including any required container nodes, the label, per-field errors (if supported) and hints etc. The output depends entirely on the UI Set in use.The tag supports named fields or "bean" fields where the value comes from a bean in the current page scope. UI Sets will typically use the Grails Fields plugin to do this, but UI Sets are free to use any implementation.<ui:field name="field1" type="text" hint="This is a little hint" label="Text field"/> <ui:field name="field2" type="checkbox" hint="This is an error hint" label="Checkbox field with an error" error="${true}"/> <ui:field name="field3" type="radio" label="Radio field"/> <ui:field name="field4" type="textarea" label="Textarea field">Hello world</ui:field> <ui:field bean="${form}" name="name"/> <ui:field bean="${form}" name="enabled"/> <ui:field bean="${form}" name="dateOfBirth"/>You can see that the field type is auto-sensed, which can be overriden with "type".Note that there are related tags input, fieldLabel, fieldInput, fieldErrors, fieldHint
Image
The image tag is used to render images that represent content for the user. UI Sets might add some classes, caption or other decoration, perhaps a light box that allows zooming in to a larger version of the image.<ui:image uri="/images/product1.png" width="200" title="Our latest product" alt="This is our latest product SLA-YER3000"/> <ui:image dir="/images" file="/product2.png" title="Last year's product" alt="The OP-ETH2000 is now obsolete"/>
Table
The table tag is used to render tables of information.Use just like normal tables, but gives the UI Set/Theme an opportunity to apply extra styling and functionality such as sortable columns.<ui:table> <thead> <tr> <ui:th text="table.id"/> <ui:th text="table.artist"/> <ui:th text="table.title"/> <ui:th text="table.genre"/> </tr> </thead> <tbody> <g:each in="${1..10}" var="i"> <ui:tr> <td>${i.encodeAsHTML()}</td> <td>Farmers Market</td> <td>Slav To Rhythm</td> <td>Jazz</td> </ui:tr> </g:each> </tbody> </ui:table>You must always use
ui:table
for Theme-compatible table styling.Messages
The message tag is used render text messages such as info and warning messages.<ui:message type="info" text="alert.message.something.happened"/> <ui:message type="error" text="alert.message.something.failed"/> <ui:message type="warning" text="alert.message.something.dodgy"/> <ui:message type="debug"> <p>This is some debug output, only for development mode</p> </ui:message>As with most UI tags you can specify text/textArgs attributes or a body.There are dynamic methods added to controllers by Platform Core plugin to make it easy to display messages to the user, and this mechanism is reused in Platform UI to allow the UI Set to customise the rendering. Just call
displayMessage
or displayFlashMessage
from Platform Core:class AlbumController { def delete = { Album.delete(params.id) displayMessage "album.was.deleted" } }… and then add the displayMessage tag variant from Platform UI:
<ui:displayMessage/>This will render nothing if there is no message set by the controller. Otherwise the flash and/or request messages will be shown, using i18n resolution much like the
p:text
tag of Platform Core.Pagination
The paginate tag renders report pagination controls much like g:paginate, but in a way tha can be customised easily for theming.The attributes are the same as the normal g:paginate tag:<ui:paginate controller="books" total="${totalBooks}"/>The underlying UI Set is presented with a data structure containing the links required to render the pagination, but not the markup itself.
Tabs
Tabbed pages are a familiar and frequently UI element. You can use the tabs tag to define a set of tabs, and tab tags inside the body ofui:tabs
to define the content:<%-- Tabs with hardcoded titles and links only --%> <ui:tabs> <ui:tab titles="One" active="true" action="list"/> <ui:tab titles="Two" action="search"/> <ui:tab titles="Three" action="list"/> </ui:tabs> <%-- Tabs with i18n titles and links only --%> <ui:tabs prefix="my.tab.title"> <ui:tab title="a" controller="books"/> <ui:tab title="b" controller="books" action="search" active="true"/> <ui:tab title="c" action="latest"/> </ui:tabs> <%-- Tabs with i18n titles and inin content panels only --%> <ui:tabs prefix="other.tabtitle"> <ui:tab title="d"><ui:h4>Tab D Content</ui:h4><p:dummyText size="2"/></ui:tab> <ui:tab title="e"><ui:h4>Tab E Content</ui:h4><p:dummyText size="2"/></ui:tab> <ui:tab title="f" action="true"><ui:h4>Tab F Content</ui:h4><p:dummyText size="2"/></ui:tab> </ui:tabs>The resulting markup may be structurally very different from the UI tags you use in your page, depending on the UI Set's implementation.
Avatar
Display of user avatar images is a common feature of many web apps, especially social ones. External services typically supply the actual images, but how these are rendered/decorated is up to the application.The avatar tag renders such an avatar from a user identity string. What this string is depends on the underlying UI Set's avatar implementation, but this will often be an email address:<ui:avatar user="marc@grailsrocks.com" size="50" rating="G" title="An avatar" alt="This is an Avatar"/>
Logo
Logos are often, but not always rendered using CSS background-image. If you need to insert your application's logo as an inline image, the logo tag allows the UI Set to style or position it appropriately, with support for multi-resolution logos.<ui:logo width="450" height="150"/>The logo file is located by convention.
Navigation
Perhaps the trickiest and most variable page structures are the primary navigation menu and sub menus. The primaryNavigation, secondaryNavigation and navigation provide a markup-neutral way to render these menus in a way befitting the current theme.<div class="main-nav"> <ui:primaryNavigation/> </div> <div class="sub-nav"> <ui:secondaryNavigation/> </div>
Carousel
Carousels are a common, if maligned, feature of application sites. Typically featured on the home page they transition between a series of images or content panels.Plugins and applications can use these via UI Sets without concern for the underlying markup and JS code required:<ui:carousel> <ui:slide active="true"> This is slide one </ui:slide> <ui:slide> This is our second marketing slide </ui:slide> <ui:slide> And here is our third marketing slide </ui:slide> </ui:carousel>
6.2.2 Grouping
There are a couple of grouping elements available in UI Sets.Actions
The actions a user can perform are often gathered together in one place in a well designed form. The actions tag provides a holder for these, and allows the current theme to render this section of a form appropriately:<ui:form action="update"> <fieldset> <ui:field name="firstName"/> <ui:field name="lastName"/> </fieldset> <ui:actions> <ui:button mode="primary">Update</ui:button> <ui:button mode="cancel">Cancel</ui:button> </ui:actions> </ui:form>Any content in the
ui:actions
body will be rendered, usually in some kind of styled container, by the UI Set.Field Groups
Forms often arrange fields into groups, typically with<fieldset>
in HTML. The structural markup for this is abstracted using the fieldGroup tag:<ui:block title="section.titles.welcome"> <p>Thank you for visiting our awesome site.</p> </ui:block>It does however support rendering a title at the start of the block, using i18n.
Block
Some themes may support visually separating a block of content, for example with a "well" or other border technique. The block tag is a simple container for this purpose:<ui:form controller="book"> <ui:fieldGroup> <ui:field name="firstName"/> <ui:field name="lastName"/> </ui:fieldGroup> <ui:fieldGroup> <ui:field name="email"/> </ui:fieldGroup> <ui:actions> <ui:button type="submit">Save</ui:button> </ui:actions> </ui:form>
6.2.3 Forms
There are several UI tags specifically relating to forms, form, fieldand actions.You can create a form using the new UI tags like this:<ui:form action="update"> <fieldset> <ui:field name="firstName"/> <ui:field name="lastName"/> </fieldset> <fieldset> <ui:field name="email"/> <ui:field name="twitterName"/> </fieldset> <ui:actions> <ui:button mode="primary">Update</ui:button> <ui:button mode="cancel">Cancel</ui:button> </ui:actions> </ui:form>You can see that the GSP has no knowledge of how forms or fields or buttons are rendered. The UI Set in effect determines this. You may get completely different structural HTML and CSS classes depending on the UI Set or theme you are using.The UI Set might re-order the actions and form body or duplicate the actions as appropriate for the styling.The
ui:form
tag passes all the attributes specified to the UI Set's template for passing to the g:form tag.
6.2.4 Typography
Headings
There are UI tags for rendering heading levels 1 to 4, including support for the standard i18n mechanisms of Platform UI.This allows the UI Set/Theme or any GSP to set the base heading level for the rest of the request, so your content might use<ui:h1>
but it actually appears as <h2>
in the output. You get to maintain appropriate relative heading levels in your GSP, and let the UI deal with how this actually turns out.<ui:baseHeading level="3"/> <ui:h1>Heading level 1, or is it</ui:h1> <ui:baseHeading level="1"/> <ui:h2 title="my.sub.heading"/>