Styling and UiBinder

There are a number of tools available for styling UiBinder templates:

The styleName and addStyleNames Attributes

The styleName attribute sets the primary style for the element, replacing any primary style built into the widget.

<g:Label ui:field="lblName" styleName="special" />

addStyleNames accepts a space-separated list of style names, which wil automatically be added as if you had called the addStyleName method for each word in the list.

<g:Label ui:field="lblName" addStyleNames="special fancy" />

Without using the ui:style element described below, the styles will come from your CSS files in the war folder (or from a CSS file in your source tree under the public folder and included in your gwt.xml file using a stylesheet tag).

These two approaches are recommended in favor of invoking setStyleName and addStyleName in the associated Java file, since they provide a better separation of styling from programming code, and also simply help minimize the Java code you need to write. They're particularly useful for container elements for which you don't need any other programmatic access, so that you can apply styling to the element without making them a UI field in your Java class.

<g:FlowPanel addStyleNames="floatLeft50Pct">

The ui:style and ui:with Elements

Local (Inline) Styles

This provides for local styles, defined within the bounds of the ui:style tag, whose names are obfuscated within the local scope. The tag accepts a field attribute, whose default value is "style".

For each ui:style element, the compiler wil generate a ClientBundle and CssResource. This means that you will get a compiler error if you misspell a class name (in fact, if you wait long enough in Eclipse, you should see the offending name flagged with an error marker).

Each individual field name gets obfuscated separately, so multiple style tags can define the same style class name without a name collision (however, you would need field attributes for the style tags).

The class names you define can be used for a class attribute in an HTML binder, and styleName and addStyleNames in a widget binder.

<ui:style> .special { color: blue; } .floater { float: left; } </ui:style> <ui:style field="more"> .special { color: #aa4477; } .nice { background-color: #ffaa77; } </ui:style>

You reference these names within the styleName and addStyleNames attributes by enclosing the style name in a pair of curly braces.

<g:Label styleName="{style.special}" /> <g:Label styleName="{more.special}" /> <g:Label addStyleNames="{style.special} {more.nice}" />

Note that the curly brace syntax will actually be applied for any attribute, not just CSS-related ones. To avoid parsing of an attribute (like text) that might contain curly-braces, the opening brace can be escaped by doubling up: {{.

Non-local Styles

CSS files can be retrieved from your source tree using a src attribute on a ui:style tag. These would be plain CSS files, not in a ClientResource/CssResource. They would be located under your source tree, not under the war directory.

To reference and create a CssResource from the file NoBundle.css in the css subpackage of the this binder's packge:

<ui:style src="css/NoBundle.css" field="nobundle"/>

Including Styles from a CssResource

You can also obtain a CssResource to use within a binder template, by using the ui:style element. The type attribute specifies the fully-qualified name of the CSS resource class. GWT's code generator will create a client bundle for you, where the CSS resource style rules are supplied by the content of the tag, instead of a file referenced with an @Source annotation. This feature opens up possibilites for separate skinning of different binders.

<ui:style type="com.steveclaflin.uibinderstyles.client.css.BundleCss" field="inlinebundlecss"> html .special { font-weight: bold; } </ui:style>

To use the resource:

<g:Button addStyleNames="{inlinebundlecss.special}" />

Including Resources from a ClientBundle

You can also obtain a ClientBundle to use within a binder template, but using the ui:with element instead of ui:style. The type attribute specifies the fully-qualified name of the resource bundle class.

<ui:with type="com.steveclaflin.uibinderstyles.client.Bundle" field="bundle"/>

Here's the bundle Java class:

public interface Bundle extends ClientBundle { @Source("css/Bundle.css") public BundleCss bundleCss(); @Source ("text/snippet.txt") TextResource snippet(); }

And the CSS resource class:

public interface BundleCss extends CssResource { public String special(); }

To access a CSS resource from the bundle, and a style name, treat the bundle method to retrieve the CSS resource as a property, and also treat the method to retrieve the class name as a property:

<g:Button addStyleNames="{bundle.bundleCss.special}" />

Note that there's no requirement that the resource values used be CSS. Anything that can be created with GWT.create can be used this way. In the code fragment below, we access a text resource from the same client bundle:

<g:Button text="{bundle.snippet.getText}" />

Note that we need to "invoke" the getText method by its name, instead of treating the get part as implied. (As opposed to how the text attribute causes the widget's setText method to be invoked in a widget tag.)

Using Non-resource Classes in a UiBinder

But wait, there's more! It turns out that you can even access an ordinary class using ui:with. The same treat methods as properties approach can be used to retrieve values from the class.

If you need to pass values to the class, either as constructor parameters or using set methods, you can provide a ui:attributes child tag, using the same approach that you would use with widget tags - a tag attribute that matches a constructor parameter name, or an attribute that matches a set method.

Here's an arbitrary class we'll pull into a binder. It stores a set of image resources which can be referenced by a string name, as well as by the index of that string in an array. Note the annotated constructor, which defines the constructor that a UiBinder will use to create an instance, and also the method setExplicitDefaultIndex:

public class MyResource { Bundle bundle = GWT.create(Bundle.class); private String[] names = { "g", "m", "pg", "pg13", "r" }; private int defaultIndex = 0; private HashMap<String, ImageResource> images = new HashMap<String, ImageResource>(); @UiConstructor public MyResource(int defaultIndex) { this.defaultIndex = defaultIndex; images.put("g", bundle.g()); images.put("pg",; images.put("pg13", bundle.pg13()); images.put("m", bundle.m()); images.put("r", bundle.r()); } public void setExplicitDefaultIndex(int index) { this.defaultIndex = index; } public String getName() { return names[defaultIndex]; } public String getName(int index) { return names[index]; } public ImageResource getImg() { return images.get(names[defaultIndex]); } }

Here are two different ways to create an instance of the class within a UiBinder:

<ui:with type="com.webucator.uibinderstyles.client.MyResource" field="myresource"> <ui:attributes defaultIndex="3"/> </ui:with> <ui:with type="com.webucator.uibinderstyles.client.MyResource" field="myresourceexplicit"> <ui:attributes defaultIndex="3" explicitDefaultIndex="2"/> </ui:with>

The first element creates an instance of the class using the constructor parameter to set the default index to 3. An unfortunate side-effect of the UI constructor concept is that we must always supply the default index to it, even if we are going to replace it with an explicit value, as in the second case.

And here's how we can use those items:

<g:Button text="{myresource.getName}"/> <g:Button text="{myresourceexplicit.getName}"/> <g:Image resource="{myresource.getImg}"/>

Here is an Eclipse project that demonstrates a number of different aspects of UiBinder styling, including the above examples.

Note that in order to minimize the file size, the gwt-servlet.jar file is not included. After unzipping and importing into an Eclipse workspace, you can usually reinstate it by going to the project's properties, under the Google ... Web Toolkit sections, removing the check from Use Google Web Toolkit, then OK. Then go back through the same process to put the check back and OK again.