Polymer + Meteor + React: Impressions

I’ve been using React and Polymer together in my Meteor app, and I thought I would share my impressions of how this is going so far.

I should note that I’m working in a Meteor 1.2 environment, I’m looking forward to seeing how well this works in 1.3 but I can’t go there yet.

My motivation for using Polymer is that I wanted good support for accessibility and mobile web in my app, and after evaluating a bunch of competing widget libraries (including writing sample apps with them) I found the Polymer had good (but not perfect) support for both of these. Most of the libraries I looked at failed to support simple recommended practices such as focus trapping for modal dialogs.

Choosing Polymer also kind of dictated the choice of React rather than using Blaze. There are a number of difficulties using web components with Blaze, such as the fact that it reserves ‘template’ as a keyword. I also wanted an excuse to learn React since that seems to be the direction Meteor is headed. (A third reason is that I have found React’s architecture to be somewhat less ‘magical’ than Blaze, or at least the magical behaviors seem easier for me to reason about - particularly when it comes to implicit variables and properties accessed via this.)

Fortunately, there’s very little functional overlap between the Polymer elements and React components, each seems to fill a niche left open by the other.

Polymer components are added to the project using bower, and the compiled/bundled into the app using the differential:vulcanize package. This runs the Polymer ‘vulcanize’ command on each meteor build to create the client bundle. My only complaint so far is that it’s a little slow - it adds a second or two to each Meteor refresh, even for code changes that have nothing to do with Polymer.

The config.vulcanize file is used to select which Polymer components you want in your app. You can see mine here.

Embedding Polymer’s custom elements in React components is relatively straightforward, as seen in this example. So far, I have not had the need to wrap each polymer element in it’s own wrapper class, I just use the bare HTML elements like paper-button directly in the .jsx file.

One minor “gotcha” is that while React normally requires you to use className rather than class for native HTML elements and React components, this does not work for custom elements - you have to use class. So you have to remember which attribute name to use depending on the type of element.

Handling Polymer events: Polymer widgets emit their own special events, for example paper-button emits a ‘tap’ event when pressed. While one can listen for ‘click’, this is not recommended - the tap event includes special handling of touch events and keyboard activation, and you lose a lot of the accessibility support if you subscribe to ‘click’ directly. (This is part of why I chose Polymer - I’m very much into the model where low-level events are transformed into higher-level events as they bubble up the DOM, and where the app itself never sees native browser events.)

Initially, the way I handled this was to manually listen for these events in my componentDidMount() function, however this created a lot of boilerplate and was cumbersome. The Polymer framework has its own means of listening for events via the Polymer() function, however I didn’t want to use this either because it wasn’t very react-like: it would force my application’s structure to be very different than the typical React-based app.

Eventually what I did was create a React mixin class that looks for attributes such as on-tap="handlerName" and routes those events to the specified handler method. This is a bit of a hack due to the fact that events originating from web components aren’t properly bubbled in React’s DOM, so the mixin adds individual listeners to each element - that is, it uses querySelectorAll() to search for elements with the on-eventname attribute and calls addListener directly.

One other issue I ran into is that Polymer makes heavy use of custom CSS attributes to pass style parameters into the shadow dom. Currently these have to be inlined in the HTML and cannot be in external stylesheets, which is not as nice as having all of the styles for a component be in a single .scss file. Fortunately, the number of custom styles I have needed so far is very small.

Icons: I’ve been making heavy use of the standard polymer icons, iron-icons. This is a set of several hundred SVG icons which you can use - so far I haven’t needed to create any of my own artwork. Referencing an icon in the HTML is usually a matter of simply adding an attribute such as icon="cancel" to the paper-icon or paper-icon-button widget.

I’ve also been making use of Polymer’s flex layout system, iron-flex-layout which abstracts away the browser quirks for using CSS flex boxes.

Anyway, I’m pretty happy with the results so far, it looks nice and there’s a lot of existing widgets to choose from.

3 Likes