Introduction
I’ve spent the past 2 weeks of my vacation playing with JavaScript, Polymer, Node, Express, Restify, and Mongo. Today, I wanted to cover the fun I had with Polymer, Google’s web UI component framework, contrast it with other frameworks, and give my general impressions. From this you’ll have a firm understanding of what Polymer is for, how to use it, and what things to watch for.
What is Polymer?
Polymer is Google’s open source web component UI framework. The goal is to allow developers to utilize the latest web standards for web components in a cross browser way, today. Web components is an umbrella of standards, specifically Shadow DOM, Custom Elements, and HTML Imports.
These are the core technologies needed in browsers to build web components. Given the web community is “design by committee”, it’s actually quite a fast moving standard in that context, thus much has changed between Polymer version 0.5 and version 1.x. That said, Google’s done a great job of shielding you from a lot of these core changes as well as including new features that iterate on top of previous work.
… the whole point of creating a UI framework, heh.
In short, Polymer allows you to create your own UI controls more easily than you could in the past, built on web standards, and with performance in mind. That, and they already follow the Material Design guidelines.
What does the code look like in practice?
While this is native in browsers now:
Results in this:
You can now do this:
And you’ll see this:
Notice in Bootstrap, you have to apply the CSS classes to the tag:
Unlike Bootstrap, and like Atomify, Polymer’s goal is encapsulate everything; not just the CSS, but also the JavaScript functionality, and additional HTML tags that make it up.
You’ll see a common theme with Polymer is mainly focused around markup, specifically HTML tags. If you come from Angular or React, you’ll immediately get that concept of creating your own elements to use. Polymer is the same way.
The reason for this is attempting to mitigate “div soup”, where you have a lot of nested divs that use CSS styles create the user interface, as well as helping create semantics: allowing various technologies to glean meaning from your page. The semantics help for Search Engine Optimization, Accessibility, and even during development to lessen the cognitive overhead from developers and designers.
Contrast how GMail is built:
Versus using custom components:
Although Polymer’s nomenclature is about “tags” and “custom elements”, what you’re really doing is creating “components”: visual and non-visual.
Why Even Do This?
Components, Composition, Encapsulation, and Design.
Components: It’s How Interfaces Start
Once you’ve got a few applications built under your belt, you start recognizing 2 patterns that emerge every project. You have a visual style guide, whether official or unofficial, that you follow. How buttons look, work, what colors the button is vs. the text, and its shape are all examples of the minutiae.
The other pattern is re-use. This is not just a programming concept related to DRY, but a design one as well. The rule is you’re supposed to use the same UI controls for the same user actions so users can more easily use your application. Jakob Nielsen covers that in the “2. Inconsistency” section of his Top 10 Application Design Mistakes article.
Whether using Angular, React, or Polymer, you’re going to create 1 button, 1 time, and use it every where in your application a button is needed.
This applies to all user controls. Polymer’s core concept is building these components while providing many of which you need out of the box so you don’t have to create everything from scratch. That said, if you wish to opt-out of Material Design, you can use the core web component libraries it provides to use your own look and feel.
Composition: It’s How Interfaces are Made
Once you have your components built, you then start composing them together into large components that house other components. This is called composition, using something in another thing. You either build more complex components using these pieces together, or build containers. This can be a customized button inside of a calendar control:
Which is created by one HTML tag:
or a button and a text field input inside of a self-contained login form:
Which is also created by one HTML tag:
Lastly, you’ll sometimes create containers that house dynamic content and use HTML’s declarative nature. Polymer’s <paper-card> is a perfect example. Not only can you house custom content, they also gave you 2 areas for it to live, the ‘content’ and ‘actions’ area for buttons:
Like Angular’s ngTransclude, or Backbone Marionette’s Regions, you simply use a <content></content> tag in your component, and that’s where stuff will go.
The more complex the components and screens, the more composition and containers you’ll create. Polymer easily enables composition and containers.
Encapsulation: D0 One Thing Well and Don’t Tell Anyone How You Do It
While functional & reactive programming are in, Object Oriented Programming is still how most projects are primarily done and how most programming is still taught. Good OOP is when you create components that have a well understood API and don’t leak too much detail and state.
Doing that in HTML, JavaScript, and CSS is really hard. HTML’s DOM API makes your document an open book. Tag ID’s and class names are effectively global variables, and cannot clash. JavaScript has no module API nor built-in ways of privacy without working around how JavaScript works. CSS is SUPPOSED to cascade; that is a core feature of CSS.
Polymer attempts to fix the encapsulation problems the web has.
HTML
Shadow DOM enables you to hide DOM from the document. Just like you can’t open a native <button>, your normal DOM API code won’t dig into your component.
CSS
This is in flux, but similar to HTML, the CSS styles you define in your Shadow DOM only apply to that component. They don’t leak out and overwrite other styles. Conversely, you effectively have an umbrella from cascading styles so your component’s styles aren’t overwritten if they have the same names of something else. You can confidently put your component in any other application and be assured it’ll look the same.
JavaScript
Beyond making Object.prototype easier to work with, they don’t do much here since the web component has a lot of other solutions for this. However, they DO make it easier to import via HTML imports. Whether your code is code or visual code, both can be imported using the same tag.
The work Google has done with Polymer means you only have to do 2 steps to use a component you or someone else has written: import it and use it.
Import:
And then use it as normal HTML, in the light dom or shadow dom:
Or via JavaScript:
That is way easier than the copious DevOps, transpilers, and module libraries I and others use today. This is also why Angular Dart years ago went to the component model, and where Angular 2 is going with class annotation. While functional is in, the basic concepts of modules, package organization, and encapsulation are still valid, good concepts to use and build applications with.
Design the UI, it Then (Mostly) Builds Itself
Designing applications is different from designing websites. The web development world is vast, complex, and there are a variety of approaches. The only consistency I’ve seen regarding design is that those building applications tend to encapsulate their design into the components they use to build applications whereas the web designers tend to do this from their CSS/LESS/SCSS.
Polymer is clearly on the developers side on this one in that embracing Shadow DOM, I can layout my component’s visual pieces, code it to work, and style it all in the same place. Once I distribute it, I don’t have to worry about style names that make sense, how the CSS is organized, what build task I use to re-compile the LESS, etc.
Instead, you either just code the CSS inline with your component with confidence you aren’t negatively affecting another component, or you use common styles which are a safe, opt-in approach. That way, if you want to share a single style sheet, or support theming, you can do that without breaking encapsulation.
At this point, you help mitigate the biggest problem Web Designers have: Developers.
Most developers I’ve met say they care about design, but in practice don’t. This isn’t malicious, they’re just focused on their job and that’s making things work. They’re held accountable when they don’t work. If the color or font is wrong? That’s ok. Doesn’t compile or show the data correctly from the database? That’s not ok.
This culture reinforces developers to stay away from design concerns unless they have too since a lot of design changes can’t easily be unit tested like their code can.
With Polymer, once you hand a developer a component with the padding, fonts, and colors already correct, it’s pretty hard for them to screw that up unless they dive into the source components. For a Designer, that’s powerful. For a Developer who hates CSS or loves design but doesn’t have time for it, it’s awesome. For a Business Analyst, that’s less JIRA tickets that pollute the backlog and never get done in time for people to remember what the ticket was referring to.
Additionally, for other designers, you can expose components via variables to allow them to break through the Shadow DOM in a clean and well documented manner, yet still abstract the implementation in case you have to refactor the component later.
Components enable designers to ensure the building blocks developers use aren’t as easily broken, and developers in turn don’t have to worry as much about “Crap, I forgot to re-add that CSS class which I can’t remember it’s name after I refactored that partial.”
So… Why Again?
Interfaces for applications are built using components. Polymer makes it easy for you to build components using JavaScript, HTML, and CSS by keeping them in the same file.
Application interfaces are typically built by composing components within components to create more complex views and screens. Polymer can use Polymer components inside of Polymer components. You can also create containers to enable this dynamically.
Polymer encapsulates HTML names and ID’s via Shadow DOM ensuring you don’t have naming conflicts that break your application without a runtime exception letting you know it break based on some random design change. It also encapsulates your CSS there as well, inverting the control of how CSS works, ensuring the only CSS changes you can make are opt-in, or explicit via easily found keywords like /deep/, or developer created variables.
For Developers, it enables easier encapsulation and adherence to OOP concepts by making it easy to re-use the visual and non-visual components you create.
For Designers, it helps ensure their CSS is harder to break by developers who don’t know any better by wrapping them in core building block components the developers don’t need to go into.
How Do I Use It?
I chose the hard way. I suggest you have more fun and choose the easy ways.
First, check out the Yeoman generator-polymer. It’ll get you up and running fast, and has a build system already setup for you.
Second, if Yeoman ain’t yo thing, go straight to the Starter Kit (it’s what the generator helps get started for you).
Third, you can just go straight to the Seed Element to get up and running with something simple and smaller locally to play with.
Fourth, what was most enlightening for me was to build a component using the 0.5 docs “Your First Polymer Application“. They haven’t been updated for 1.0, but if you don’t mind hitting the migration guide, it still gets you 90% of the way there with the core concepts.
Fifth, Rob Dodson has a great YouTube channel called Polycasts where he goes over building Polymer components and covers everything and builds on earlier content.
Polymer Gotchas
Here some of the things that threw me for a loop.
Events
When you read the docs for the iron and paper elements, they have properties and method documentation, but NOT events. As someone who builds GUI’s, this seems like a glaring oversight. To fix it, first, memorize how events work via the fire method.
If someone goes:
Then you know the event to listen for is ‘on-change’:
Every single one of the paper elements links directly to the source code. Dig in there for a “fire” method. If you don’t find it, then see which behaviors it implements (think Decorator pattern or multiple inheritance ) and find their source code in the Polymer repo via the search function. Otherwise, scroll back to the top, and see what components it’s using. The fire method bubbles by default, so the components its using by composition could be the ones who actually fire the original event.
Remember, fire(‘moo-cow’) results in a <component on-moo-cow=”onWubWubWub()”></component>. If you use camelCase instead of dash-case for fire events, you’ll drive yourself nuts when things don’t work.
animationConfig Placement
I lost 2 days trying to get animations to work because both times I put it outside of the properties object. It’s supposed to go inside. If you think I’m not a moron, please +1 this PR.
Non-Visual Components
Once you start getting knee deep in building visual Polymer components for a few days, you forget that you could build non-visual ones as well. Since you can only use inheritance on native controls, most of your code will be composition: enhancing existing tags.
Core Things Nobody Tells You About
If you’ve been building applications on the front end for awhile, you start to have some expectations on where the basic things are. Here they are.
Ajax/XHR/HTTP Requests
Use iron-ajax.
Making selectable lists
Use iron-selector.
Pub Sub
If you miss your _.trigger or $rootScope.$broadcast then use iron-signals.
Basic CSS Layout
Read the source for iron-flex-layout, and remove the dashes in your head. This allows you to do everything you could in 0.5, except using the class attribute.
This:
Becomes this:
Responsive Layouts / Media Queries
When you’re building components or screens that have 2 layouts, you use the iron-media-query inline. If you start duplicating markup for each media query, just refactor it to a component.
Icons
There’s like 5 icon classes… ignore them. Just install iron-icons, then import the ones you need or all of them. To see which ones are available, navigate to the bower_components/iron-icons/demo/ folder on your local web server to see which ones you can use.
ALL of the icons use the same naming structure: “category:name”, whether an iron-icon or a paper-icon-button. So if you see the icon attribute, that’s what the icon name really means.
Infinite Scrolling List
… ah, the question you wish C# developers would ask you on interviews vs. red/black tree sorting… *ahem* If you need one, use iron-list.
Images
They have a really cool uber-image component called iron-image. Way better than img tags.
localStorage
They have a nice wrapper around localStorage called iron-localstorage that would of saved me a lot of time. Basically allows you to use Polymer’s built-in data-binding with localStorage.
Routing
Polymer doesn’t ship with a router. They did in 0.5, but in 1.x they assume you’ll use a router that’s right for you. There are a few Polymer specific ones on Github and CustomElements.io.
I tried a few, but none work with the way I work with Mediator View’s doing most of the heavy lifting. Some weren’t declarative enough or didn’t support custom <templates>. Worse, the majority only supported 0.5, not 1.x.
I attempted to wrap Angular’s UI-Router in a component, but got frustrated pretty quickly with the inability to easily have them talk to each other so just went with page.js. It works quite well.
Scope
Polymer focuses on HTML and CSS betterment, not JavaScript. As such, all the same problems with scope exist in Polymer script tags since it’s basic JavaScript. Everywhere you put “var me = this”. If you’re not going to use a framework, I recommend Lodash’ bindAll.
DevOps
Code Quality
The jshint works in Grunt and Gulp, but I couldn’t get jscs to work unless you externalize your script files and ignore the Polymer html files.
Injector and Wiredep
As your project grows, you’ll need some type of module system. The nice thing about Polymer is that it handles load order for you; as long as you have all your imports there, it doesn’t matter what order they are in. However, Vulcanize, the build tool for Polymer, doesn’t always work with 3rd party libraries. I use Injector (grunt / gulp ) which now embeds Wiredep so it automatically puts script tags for all your npm and bower classes.
I found running these first, then running Vulcanize afterwards excluding the build path classes in the ignorePath option seemed to work. I didn’t attempt minifiy/uglify the Polymer specific scripts as they weren’t externalized. I find while developing it’s easier to target the DOM I’m working with if it’s in the same file and I scroll up. It’d be nice to find a build way to automatically externalize the JavaScript and the CSS.
Also, I couldn’t get either of the Grunt or Gulp Vulcanize plugins to play nice with my build structure paths so just wrote raw JavaScript for it and it worked.
Unit Tests
I couldn’t get the web components tester to work. After spending hours in Grunt fighting with various missing paths, I gave up. I reckon if I had used the Yeoman generator, it’d work. I did get the sample seed-element project’s tests working though.
What About X-Tags?
Why Would I Use Polymer vs. Something Like Bootstrap or Foundation?
Polymer is part component framework, but it’s also a way to use the newest stuff, now, and help give Google feedback on direction. Since last year, Polymer has been the “living prototype” of the web components standards and has changed as both people have used it, the ideas Google has had to improve upon it, and the standards committee has started standardizing on the implementations.
Unlike Bootstrap/Foundation, you’re building real web components, not divs with decoration.
A lot of the value that Polymer provides is that it implements Google’s Material Design. If you don’t want that look and feel, you can still use most of the iron and neon animation elements and just stay away from paper.
For those of us in enterprise development building large applications, Bootstrap reigns supreme, mainly because it has all the components we need, now. Contrast that with Polymer, I had to build a Calendar / Date Picker since most of the ones I found were 0.5 only. I then found another v1 the next day. The community DOES build a lot on Github, but quality does vary, and it’s not a single project like Bootstrap’s is.
Bottom line, Bootstrap just has more of everything you need, both in design, typography, components, and layout.
Could I Use Polymer With Angular, Backbone, or React?
If you’re going to use it with Angular, try Angular Material first. You’re basically marrying yourself to Material Design’s look and feel, but most clients I know would be mostly ok with that.
If you want to do it yourself, I don’t recommend it. Angular 1.0 doesn’t yet play well with Shadow DOM, whereas Angular 2 is getting there. You get weird bugs unless you do it just right… which doesn’t really feel right. If you do forge ahead, you’ll enjoy that most of your Angular directives can merely have this as their template:
Notice it’s template, not templateUrl, which means this is a nice way to give your Polymer components Controllers… sort of. While the methods work, binding and events were hard to figure out if they were working or not.
For Backbone, things are murky. The Backbone View is basically your Polymer component’s JavaScript, and the <template></template> tag contents is the Handlebars template. Polymer already has a pub sub library, so there is no need for Backbone Events. While in theory Backbone Views could make good Controller classes, it’d be easier to just do this yourself listening for attached/detached events from your components, a la Robotlegs Context.
I haven’t tried this myself, but I know of one big bank that was investigating this approach last year mainly because they still have a lot of JSP and portals where full applications cannot be built, so instead they share mini-applications. Polymer seems a great fit for this.
After having some experience using their composition strategy, both Angular and Backbone are way harder to integrate with than I originally thought since once you’re out of the Polymer realm, things get harder to work with. Binding doesn’t work, so you have to get/set things. Events aren’t data bound, so you have to use addEventListener. Things like that. It’s just easier to live and work in the Polymer realm, and take the same approach you do in Backbone architecture: add as you need YAGNI style.
More investigation is needed as I might of missed some things or did outside world integration wrong.
React makes no sense with Polymer. They both are trying to solve the same thing: faster and easier DOM. React claims that it’s fast, whereas a lot of the Polymer justification of the <template> tag and Shadow DOM is performance. I don’t know who’s right, but both build reusable components, have data binding, have a nice component lifecycle, make the DOM easier to work with, and have no implied MVC architecture on top. It’d be easier to use React within Polymer I think, but again, I don’t see the point unless you believe the speed benefits could help in the Shadow DOM realm.
Conclusions
Polymer’s great. I like the v1.1 release a lot. Using components feels natural, and is how I built applications from my Director, Flash, Silverlight, and Flex days. While I hate CSS, I enjoy that Flexbox mostly works, and much of Material Design is already implemented for me. I like the iron and paper components I have out the box.
I’m disappointed it’s not as many as Bootstrap. I also miss all of the Angular features I’ve become accustomed to, mainly ui-router, Controllers, and dependency injection for easier unit testing. Jury’s out on DevOps. I also miss the 0.5 docs; I’m guessing the plethora of standards changes at Google is just really fast and maybe their short on documentation resources, or don’t have an easy way for open source to contribute on that front.
If I had a smaller gig where I wasn’t building a large, year long application with 20+ developers, AND I could justify the time building the missing Bootstrap components/css if any, I’d definitely choose Polymer. As someone who was forced to the web, it’s certainly made it a lot more fun to work with.
If you’d like to learn more, I’ve got a calendar component I built and a Polymer, Node, and Mongo reference applications as well.