layout | type | navgroup | shortname | title |
---|---|---|---|---|
default |
resources |
resources |
Resources |
FAQ |
{% include alpha.html %}
Don't see an answer to your question on here? Ask on the mailing list!
{% include toc.html %}
{{site.project_title}} is a pioneering library that makes it faster and easier than ever before to build beautiful applications on the web. {{site.project_title}} is built on top of a set of powerful new web platform primitives called Web Components. Web Components bring unprecedented composability, interoperability, and consumability to the web platform. The result is a monumental increase in developer productivity.
{{site.project_title}} is currently in "developer preview." However, despite the label many people have already had success using {{site.project_title}} in production. Although things might still change, we encourage developers to take {{site.project_title}} out for a test drive.
{{site.project_title}} is the embodiment of material design for the web. The {{site.project_title}} team works closely with the design teams behind material design. In fact, {{site.project_title}} played a key role in material design's development: it was used to quickly prototype and iterate on design concepts. The material design components are still a work in progress, but will mature over the coming months.
Nope! {{site.project_title}} Designer is primarily a tool to make it easy to dive in an prototype apps. It's entirely optional—although we've found that for developers who use it, it has quickly become an indispensable part of their workflow.
That's fine. The cool thing about Web Components-based libraries like {{site.project_title}} is that you can easily mix and match elements built using different libraries—and you don't have to use any of our databinding syntax if you just want to use some of our elements.
{{site.project_title}} aims to support evergreen browsers. After all, we're trying to simulate the future, and as someone once said, "You're headed for trouble if all you do is stare in the rear-view mirror." In practice, this means we support the most recent versions of Chrome, Safari, Internet Explorer, and Firefox. Chrome 36 is the first browser to ship all of the platform features {{site.project_title}} depends on natively.
Note that this is fewer browsers than other frameworks support. For example, {{site.project_title}} only aims to support Internet Explorer 10 and above. Some pieces of {{site.project_title}} may support more browsers if it doesn't require too much extra effort--if you find bugs in unsupported browsers, please still file them. Most things should work in IE9 today without too much work; feel free to file bugs on what doesn't. IE8 is incompatable due to its insufficient DOM support.
See our Browser Compatibility page for more information.
The foundation layer in our architecture diagram is based on emerging web standards. As browsers support them natively, the need for that layer will diminish and ultimately disappear. In fact, Chrome 36 is the first browser to support all of the primitives natively. It's impossible to say when every browser will support these features natively--but the more that web developers ask for them, the sooner native support will come.
One of our core goals is for {{site.project_title}} to work on modern mobile browsers as a first-class citizen. Check out Topeka, one of our sample apps, to see it in action.
By combining data-binding, core-scaffold, core-pages/core-animated-pages, and <flatiron-director>
(an element for routing), you can easily create a responsive SPA with deep linking.
x-tags is a cool project that Mozilla is working on, and it's not directly affiliated with {{site.project_title}}. However, both {{site.project_title}} and x-tags build on the emerging Custom Elements standard, which means their components are interoperable by default. Both Google and Mozilla offer polyfills for the Custom Element spec. X-Tag works on top of either, so you can use X-Tag custom elements alongside your {{site.project_title}} components. We're working actively with them to maximize compatibility between the component sets.
How is {{site.project_title}} different from Twitter's Bootstrap or Adobe's Topcoat? {#uiframeworks}
Bootstrap and Topcoat are awesome CSS/UI libraries. Our goals for {{site.project_title}} are different. While we have our own set of shiny UI components, the meat of {{site.project_title}} is geared towards developers interested in building web applications on top of Web Component technologies. {{site.project_title}} also provides additional sugaring APIs to meet the demands of today's web applications.
Nope. {{site.project_title}} isn't like things that have come before. {{site.project_title}} is the first of a new kind of library taking advantage of Web Components. The arrival of Web Components is a monumental change in web development, and we're really excited about the future {{site.project_title}} is demonstrating.
polymer.dart is a Dart port of {{site.project_title}} created and maintained by the Dart team. The Dart team is collaborating with the {{site.project_title}} team to ensure that polymer.dart elements and polyfills are fully compatible with {{site.project_title}}.
{{site.project_title}} is maintained on cdnjs and can be loaded from the following URLs:
<script src="//cdnjs.cloudflare.com/ajax/libs/polymer/{{site.latest_version}}/platform.js"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/polymer/{{site.latest_version}}/polymer.js"></script>
There are a number of reasons why we recommend you use Bower instead of the CDN:
- The CDN does not host polymer.html which removes the ability for elements to import it.
- There are many elements which are not hosted on the CDN so it might be tricky to include all of them in your project.
- You will not be able to Vulcanize your code.
One limitation of today's polyfills is that {{site.project_title}} aggressively uses XHR to shim HTML Imports. We're experimenting with packaging systems and build steps to reduce the cost of network requests. HTML imports are supported natively in Chrome 36 this API lands natively in browsers, where things will Just Work™. Resources load as they normally do, taking advantage of parallelism, browser caching, etc.
You can try Vulcanize, which is a build tool for concatenating a list of elements and inlining their definitions into your main page.
Deeply. And we want the entire web platform to be a buttery smooth 60fps. That said, we have not yet run benchmarks on the various polyfills--we're in the early stages, after all! If you're interested in helping us put some numbers behind these guys, let us know.
Remember our libraries go away over time! {{site.project_title}} gets better, stronger, and faster as native browser implementations pop up.
Minified and gzipped, platform.js is ~44KB (for comparison JQuery 1.10 is 32KB). Keep in mind that most of this size comes from the polyfills; code which has a death wish and goes away over time as browsers support the native APIs.
{{site.project_title}} has also been designed to be a la carte. For example, if you're only interested in Custom Elements, use the custom elements polyfill. If you only want Shadow DOM, use its polyfill. platform.js is simply a convenient bundle for developers that includes all of the the pieces for building {{site.project_title}}-based applications.
Yes. Here's an example Polymer Chrome App to get you started. It's important to note that Chrome Apps have a strict Content Security Policy (CSP) which prevents the use of inline script elements. To handle the CSP limitation, this example uses our Vulcanize build tool (in the form of grunt-vulcanize) to turn inline script elements into external files. Be sure to read the FAQ section on Content Security Policy and the Dealing with CSP section in the sample project's README.
Yes. By using platform.js
and creating elements that use external scripts, {{site.project_title}} runs under CSP. If you prefer to keep your element's
script inline to <polymer-element>
, we recommend using Vulcanize and running with the --csp
flag.
In other nuanced cases, {{site.project_title}} fails under CSP. This is because the HTML Imports is polyfilled using XHR, which can in turn, execute strings as JavaScript and fail CSP. So if you import a file that has an inline script tag, it will fail. This problem will go away with native HTML Imports (see Blink's crbug.com/240592 tracking bug).
We love to hear your comments or suggestions. File a bug or swing by the mailing list and say "hi"--we don't bite! If you want to contribute code, see our contributor's guide.
We have many different demo, platform, and library repositories. If you know exactly where the problem lives in the stack, please file the bug under the appropriate repo. Otherwise, filing under the general {{site.project_title}} project is great.
There is no way to guarantee sharing and deduping in the general case. However, if you have a library of components that use a library, they can all import a "library.html" file that loads that library. HTML Imports will de-dupe the import based on it's fully qualified path.
If multiple libraries want to share a dependency, they will have to agree on a system. Feature detection, or an agreed upon common location for a 'jquery.html' file in a CDN, etc.
{{site.project_title}} uses Chromium's continuous build infrastructure to test the entire system and each polyfill, individually. See our build status page.
One way to validate input is to use a *Changed
handler on to observer the
property changing, but separate out the "set value" vs. the "validated value":
<polymer-element name="x-foo" attributes="color">
<template>
Do you like the color <span style="color:{%raw%}{{validColor}}{%endraw%}">{{validColor}}</span>?
</template>
<script>
Polymer('x-foo', {
color: 'red',
colorChanged: function(inOld) {
if (this.color.match(/red|orange|yellow/)) {
this.validColor = this.color;
} else {
alert("The color wasn't a hot!");
}
}
});
</script>
</polymer-element>
<x-foo color="orange"></x-foo>
For example <polymer-element name="my-element" extends="foo bar">
.
No. But {{site.project_title}} may provide a syntax for mixins in the future.
{{site.project_title}} has many different pieces. Creating a one-stop-shop .zip for all of the different permutations is unwieldy. If you really want a .zip, Github provides a download link on each project page. However in some cases, you won't get the necessary dependencies and will need to do this on multiple repositories.
Web components and {{site.project_title}} are intended to be extremely granular. This is on purpose, to allow users to use exactly what they need and nothing more. In additional to granularity, higher-level components may be composed out of lower-level components. Bower allows us to easily manage those dependencies.
{{site.project_title}} tries hard to mimic native Shadow DOM, in that nodes with the same
id
s will still be encapsulated.
However, you should avoid using DOM-level id referencing (e.g. <label for>
) when using {{site.project_title}}. The id
may not resolve correctly when under the Shadow DOM polyfill.
I'm trying to render HTML using data-binding but {{site.project_title}} escapes the content. {#setinnerHTML}
{{site.project_title}} does not stamp unescaped HTML via data-binding because it becomes a vulnerability for XSS attacks. Instead, you can use a property changed watcher and automatic node finding to set the .innerHTML
of an node:
<div id="div"></div>
dataChanged: function() {
this.$.div.innerHTML = this.data;
}
When using <template repeat>
, a similar approach can be taken as suggested in stackoverflow.com/a/22311788.
Until the addition of HTML <template>
, certain elements like <select>
, <table>
, and others had special parser rules to prevent anything other than <option>
and <tr>
from being their children, respectively. Because of these legacy rules, browsers that don't support <template>
will lift unexpected elements out of context and make them siblings, including <template>
itself!
For example, the following won't work correctly in browsers that don't support <template>
:
<!-- Won't work in browsers that don't support <template>. -->
<table>
{%raw%}<template repeat="{{tr in rows}}">{%endraw%}
<tr><td>...</td></tr>
</template>
</table>
The <template repeat>
is hoisted out and rendered as a sibling:
<!-- Unsupported browsers make the child <template> a sibling. -->
{%raw%}<template repeat="{{tr in rows}}">{%endraw%}
<tr><td>...</td></tr>
</template>
<table>
...
</table>
For browsers that don't support <template>
, the TemplateBinding prollyfill has the ability to repeat <option>
and <tr>
directly using the template
attribute:
<table>
{%raw%}<tr template repeat="{{tr in rows}}">{%endraw%}
<td>Hello</td>
</tr>
</table>
Another example using<select>
/<option>
:
<polymer-element name="my-select">
<template>
<select>
{%raw%}<option template repeat="{{options}}">{{}}</option>{%endraw%}
</select>
</template>
<script>
Polymer('my-select', {
ready: function() { this.options = []; }
});
</script>
</polymer-element>
<script>
var select = document.createElement('my-select');
select.options = ['One', 'Two', 'Three'];
</script>
If your users are using browsers that don't support <template>
, use the template
attribute on these special elements.
Note: browsers with native support for <template>
allow it to be a child
of elements <select>
and <table>
. If you know your users are using a browser
with support, write your repeaters like this:
<table>
{%raw%}<template repeat="{{tr in rows}}">{%endraw%}
<tr>
<td>Hello</td>
</tr>
</template>
</table>
How can I access the current named model instance that in a <template repeat>
? {#templateinstancemodel}
For example, in a on-*
handler, you can access the named model instance using: e.target.templateInstance.model.<property>
:
{%raw%}
Sure can. Here's a demo.
{%raw%} {%endraw%}
The behavior is similar to templates in non-template browsers in that their content is not inert. For example, scripts will run.
If Object.observe()
is available, data changes happen ~immediately at end of a microtask.
When Object.observe()
is not supported, {{site.project_title}} uses its polyfill (observe-js) to poll and propagate data-changes throughout the system every 125ms.
Instead of waiting for the next poll interval, one can manually schedule an update
by calling Platform.flush()
. There are very few cases where you need to call Platform.flush()
directly.
Note: on platforms that support Object.observe()
natively, Platform.flush()
does nothing.
Use a custom build step that flattens/concatenates everything into a single file,
then use HTML Imports (<link rel="import">
) to
bring that file into your app.
Similarly, you could write a build step that inlines any custom element definition directly into your main app. We've experimented with this basic idea in a tool we call Vulcanizer.
Because Polymer makes use of polyfills, search engines should treat Polymer-based applications no differently than they do other javascript-based web apps. In fact, Google's crawler understands JavaScript heavy applications. Going forward, it is a reasonable assumption that as use of native Shadow DOM increases, search engine providers will try to adapt to understand it, just as they have adapted to other new web technologies in the past.
At http://customelements.io, you can find a growing registry of third party components and contribute yours too.
Unfortunately, this is a limitation of the HTML Import spec and the polyfill follows suit. The polyfill uses XHR to pull down external imports. These will fail if they are not CORs-enabled.
{%comment%}
See "Making styles global". {%endcomment%}
By default, customs elements are display: inline
. The fix is to give your element
a default style of display: block
using :host
.
<polymer-element name="my-element">
<template>
<style>
:host { * { display: block; } }
</style>
...
</template>
...
</polymer-element>
<script>
window.addEventListener('polymer-ready', function(e) {
var element = document.querySelector('my-element');
// element.clientWidth/clientHeight won't be 0.
});
</script>
For a <content>
, you can iterate through content.getDistributedNodes()
to get the list of nodes distributed at the insertion point.
In {{site.project_title}}, the best place to call this method is in the attached()
callback so you're guaranteed that the element is in the DOM tree.
Also remember that you can access the light DOM as the element's normal children
(i.e. this.children
, or other accessors). The difference with this approach
is that it's the entire set of potentially distributed nodes; not those actually distributed.
Because of subtle timing issues on element upgrades, it's generally a mistake to attempt to reference an element's children (light dom) in the created()
, ready()
, or attached()
method. When these methods are fired, the element is not guaranteed to be in the DOM or have children. In addition, {{site.project_title}} calls TemplateBinding.createInstance()
on an element's <template>
to create its Shadow DOM. This process creates and binds elements in the template one by one.
The best time to take a first look at an element's children is in domReady()
. This is when the element is in the DOM, has a parent, its possibly children. To observe changes
to light DOM children, setup a mutation observer.
The attached()
callback is the best time to access an element's parent.
That way, you're guaranteed that the element is in DOM and its parent has been upgraded.
Use the attached()
and this.async()
to ensure you're in the next quantum of time (e.g. the DOM has been constructed):
attached: function() {
this.async(function() {
// this.parentNode is upgraded
});
}
To manage this dance with more convenience, {{site.project_title}} provides
domReady()
to do the same thing:
domReady: function() {
// same
}
To know when light DOM children are added or removed, setup a Mutation Observer to do so. {{site.project_title}} puts a onMutation
callback on every element which can be used to
observe a single DOM mutation:
ready: function() {
// Observe a single mutation.
this.onMutation(this, this.childrenUpdated);
},
childrenUpdated: function(observer, mutations) {
mutations.forEach(function(record) {
console.log(record.addedNodes);
}.bind(this));
}
To observe other types of changes, setup your own MutationObserver
in ready()
:
ready: function() {
var observer = new MutationObserver(function(mutations) {
...
}.bind(this));
observer.observe(this, {childList: true, attributes: true});
}
By design, constructor
puts the constructor's name on window
. If you don't want
this, there are two options:
- Don't use the
constructor
attribute. Usedocument.createElement()
instead. - Use
document.register()
and wrap the constructor it returns in a namespace.
Note: Steve Faulkner had a nice writeup on this topic a while back and found that it does. See also Marcy Sutton's more recent "Accessibility and the Shadow DOM".
A common mis-conception is that the Shadow DOM doesn't play nicely with assistive technologies. The reality is that the Shadow DOM can in fact be traversed and any node with Shadow DOM has a shadowRoot
property which points to it's shadow document. Most assistive technologies hook directly into the browsers rendering tree, so they just see the fully composed tree.
In fact, if you inspect one of the native HTML elements that use Shadow DOM, <input type="date">
for example, you'll notice aria attributes inside the tree:
Other types of assistive tools like Chromevox will need to be updated to learn how to traverse the Shadow DOM. There's an ongoing discussion with accessibility experts on how best to integrate Shadow DOM with screen readers and search engines and further progress in this area is likely to come in the future.
Shadow Roots have their own activeElement
, which you can access internally as
shadowRoot.activeElement
.
This is an artifact of the Shadow DOM polyfill. It creates wrappers around DOM elements
and exposes only the standard DOM APIs (e.g. querySelector
) on those wrappers. {{site.project_title}} sets up properties on these wrapper objects, not on the actual DOM object. Since the DevTools
only knows about the actual DOM, your element properties won't be seen by the tools.
Tip: select a node in the inspector can type wrap($0)
into the console. You'll
get the wrapped node with all the {{site.project_title}} goodies attached. You can also
use unwrap()
if you need to go the other direction.
{: .alert .alert-info }
Under native Shadow DOM this isn't an issue. Properties will auto complete in the console.
Custom elements in templates are like <script>
and friends--inert. Their definitions are registered but the elements are not upgraded. Upgrading elements in a <template>
would be a performance penalty.
Special thanks go to GitHub user md_5 who generously donated the {{site.project_title}} organization name.