Building a User Interface with Google Web Toolkit
March 4th, 2011 by Gage Pacifera
I spent the past couple of weeks creating a new user interface for a project that was built using Java and Google Web Toolkit. I thought I’d share my experience integrating a new UI with the GWT framework for those who might be thinking of doing something similar.
A few caveats: I’m a front-end developer and this assessment comes from the perspective of somebody who doesn’t do back-end code. I’ve worked on a lot of projects where I’ve helped put together UIs by looking over the shoulder of the middleware developer but this is the first one where I’ve actually had to get my hands dirty with Java code. There were a whole set of challenges there, but I’ll ignore those and just focus on the GWT-related issues.
Also, the project was mostly built on GWT 2.1, and as of this post, there is already a newer version available. So there may have been some changes made that address some of the issues I mention below.
Before I go into details, I’ll give a quick summary: I think Google Web Toolkit (GWT) is a great tool for rapid prototyping. From a back-end developer perspective, it simplifies binding data to UI elements and allows you to easily throw pre-formatted HTML widgets and panels onto the screen. You can build a totally usable, user-testable app without having to think too much about making the UI work. From a front-end developer perspective, the code GWT generates is hard to deal with, especially with certain widgets that I’ll mention below. Certain elements are nearly inaccessable to styling leaving you stuck with the imprint of Google’s trademark “style” on your page. Transitioning from your rapidly-prototyped GWT project to a nice-looking web app is probably going to involve tearing out and replacing a lot of those GWT elements you used.
The Code Spew
My first unpleasant surprise working with Google Web Toolkit was seeing the ridiculously nested spew of divs within divs within tables within divs within tables (you get the idea) that the panels generate. Here’s an example:
So as a front-end HTML developer, how in the world do you take that table that’s actually a series of tables within tables within tables and mold it into something that looks halfway decent? The answer is either “with great difficulty” or “you don’t: replace the widget with something usable.” For this project I ended up going both ways. Ideally, we would have replaced all of the problematic panels (read: most panels) but the back-end development team didn’t have time, so I just had to deal with a lot of it.
The panels and widgets use a lot of HTML tables and as we all know, using tables for layout is bad. Tables do produce a more inherently structured and consistent layout, so I understand why Google would go that direction.. but if you’re trying to make your site accessable, W3C-compliant, easily stylable and SEO-friendly, then you may want to steer clear of GWT.
The Panels I Learned to Love
My bit of advice to back-end developers using GWT: use the HTML panel wherever you can. It’s basically just a widget that allows you to put freeform HTML inside of it, which is great for integrating UI elements. It’s super flexible and doesn’t produce the nested divs and tables that the other widgets do. I ended up replacing all of the GWT widgets I could with HTML Panels.
Also, the dialog box turned out to be really easy to style, so feel free to use that.
The Worst Offenders
Dock panels and scroll panels were really hard to work with. Google puts a bunch of styles right on the divs for those that apply to absolute positioning and overflow and such. As a front-end developer, you learn to hate it when styles are put right on the div elements because it means you can’t override those styles with CSS. So don’t use them unless really necessary and if you do, expect to have to work with your UI dev later on to restyle them properly.
The horizontal panels and vertical panels produce tables.. and if you put another widget within those then you get another table nested within.. and if you continue to layer widgets inside you end up with deeply nested tables that are hard to work with. I’d say don’t use the vertical panels at all as they don’t really have much advantage over an HTML panel. As for the horizontal panels, use them sparingly and try not to nest any extra widgets within them.
I didn’t deal much with the disclosure panel, but it seemed pretty locked-down in terms of style. I went with a more flexible solution of using jQuery to control my hide/show elements.
The decorator panel is silly, but not really a worst offender.. clearly if you’re using GWT you don’t care too much about how your app looks, so just bypass that and use an HTML panel instead. Your UI developer will thank you.
The Google pagination table makes things difficult for the UI developer. GWT adds classes to the various table elements, but those class names are randomly generated at run-time, so it’s impossible to target them via normal CSS. Also, the graphics used for navigation are inline base64-encoded images, meaning you can’t just sub in new images for the default images. The Java developer on my project thankfully put together a custom solution for me that linked the dynamically-generated classes with a static stylesheet and that got me most of the way. I also had to do some dynamic targeting of elements (mainly the pagination navigation) using jQuery to complete the styling.
jQuery and Dojo integrated just fine with the site. We didn’t do any deep integration between to the two; no triggering of jQuery scripts from GWT events or that sort of thing, so I can’t comment on how that works out. But you can link to your scripts in external files and in the header easily enough and run them as expected. I used jQuery for showing/hiding, some of the pagination and to style some hard-to-access HTML elements.
The exception to that is inline scripting: don’t use inline scripts. I ran into a problem where my inline scripts were working fine in my mac dev environment in Firefox and Safari. But then when I tested in my PC environment in Internet Explorer and Chrome, those same scripts didn’t work. The solution was to pull the scripts out of the body and put them in external .js files.