Notes on Polymer Web Components
Jan 26, 2016
[Note: I found this blog post 5 months after I first wrote it. I didn't get around to publishing it at the time but decided I'd rather publish it now than delete it.]
These are some of my notes from reading through the Polymer documentation. I was using version 1.2.3 so things may have changed since then.
Basic structure
The top level element should be
<dom-module id="my-element">
(theid
must be the name of the element you are defining).Within the
<dom-module>
tag, there is a<template>
tag which contains: A<style>
tag or<link>
tag for locally scoped styles and any markup for the elementWithin the
<dom-module>
tag, you also have a<script>
tag which registers the element with thePolymer()
function.
Example of what this looks like:
<dom-module id="element-name">
<template>
<style>
/* CSS rules for your element */
</style>
<!-- local DOM for your element -->
<div>{{greeting}}</div> <!-- data bindings in local DOM -->
</template>
<script>
// element registration
Polymer({
is: "element-name",
// add properties and methods on the element's prototype
properties: {
// declare properties for the element's public API
greeting: {
type: String,
value: "Hello!"
}
}
});
</script>
</dom-module>
Registration
Custom element names must always contain a dash.
The
Polymer()
function returns a constructor for the element which can be called directly (although I don't feel that is particularly useful), alternatively you can usedocument.createElement("my-element")
, or you can use a framework or embed them directly in the HTML of the page.You can supposedly "extend" native elements like
<input>
although I don't currently know how that works, I guess it just copies all the behaviour of the original element and adds extras. To actually use them, use the original tag with anis
attribute:<input is="my-input">
Callbacks
created
: for when an element has been created but nothing has been done with it yetattached
: attached to the DOMdetached
: detached from the DOMattributeChanged
: accepts the name of the attribute that was changed on the element, also accepts a "type" although I don't know what that does, usethis.getAttribute(name)
to get the new value of the attribute
The ready
callback is unique to Polymer. It is called after the local DOM has been created but before it has been attached to the DOM. Order of callbacks:
created -> children ready -> ready -> attached
Use the hostAttributes
property in the Polymer constructor to make an element have attributes when created in HTML. I do not know what the purpose of this is. Maybe you might want to set tabindex
on something so that it doesn't get focus.
Polymer.Class
can be used to create a Polymer element but not register it at the same time. Not sure why this would be useful.
Properties
Use the
properties
object in the Polymer constructor when you want to provide the ability for the user to pass down custom properties.Each key of the
properties
object is an object with the key being the name, atype
property (e.g.String
), avalue
default value.An optional
computed: "myFunction(param1, param2)"
property to define computed properties. Is only invoked once all dependant properties are notundefined
.Various other options for notifying and data binding control (
reflectToAttribute
,readOnly
,notify
,observer
).To map an attribute name (i.e. the thing in the HTML source) to a property, there are two ways to convert (these do not feel obvious and may trip me up in the future): (1) Attribute
firstname
orfirstName
goes to propertyfirstname
or (2) attributefirst-name
goes to propertyfirstName
Shorthand for simple properties which only have a
type
and nothing else:properties: {foo: String, bar: Boolean}
Observers can be added to properties by giving their name as a string and get called with the new value and old value.
You can also define an array of observers in the top level rather than one for each component. They can depend on multiple properties and nested properties. You can also use a wildcard to listen for multiple nested property changes (e.g.
observers: ['userNameChanged(user.name.*)']
).There is also a whole complex "splices" option for listening to changes in arrays.
Local DOM
Local DOM has multiple implementations. Shadow DOM can be used if it is supported, otherwise a custom implementation called "shady DOM" is used. Currently shady DOM is used on all browsers which would explain why I wasn't able to see a real shadow DOM being used in my tests.
Nodes in the local DOM are stored by id in
this.$
.For finding dynamically created nodes use
this.$$(selector)
. It returns the first node that matches the selector.The element's children are its "light DOM". They can be placed into the template with the
<content>
tag.Optionally give the content node a select attribute to select on the light DOM content matching that (e.g.
<content select="h3"></content>
).There are a whole bunch of functions for accessing the DOM found on
Polymer.dom(parent)
.this.root
is the root of the local DOM tree. Example:var toLocal = document.createElement('div'); Polymer.dom(this.root).appendChild(toLocal);
There are methods for accessing "distributed children" and "effective children" when you select different parts of your content.