One of the most powerful features of Web Components is using Shadow DOM & CSS Custom properties to achieve actual code sharing among your style guides & pattern libraries with your website and web application code. No more developing design systems in isolation and struggling to have design updates applied to the actual development code. The code you write in your Web Components is both the living pattern library and the code your components use! In this talk you'll learn the specifics of working with Polymer, the most popular Web Components library, to build your design system in a way that can be used across any web-enabled device. We'll cover best practices for working with CSS in Polymer to ensure design and accessibility needs are met. We'll also demonstrate the best ways to deal with the limitations of the Shadow DOM & CSS Custom Property shims to support older browsers.
From DevFest Florida 2017
29. “A design system’s value is
realized when products ship
features using parts from
the system.”
- Nathan Curtis
Source: https://medium.com/eightshapes-llc/a-design-system-isn-t-a-project-it-s-a-product-serving-products-74dcfffef935
35. What Are Web Components?
Polymer-Powered Design Systems - @JohnRiv35
4 Specs
36. What Are Web Components?
Polymer-Powered Design Systems - @JohnRiv36
Custom Elements
37. What Are Web Components?
Polymer-Powered Design Systems - @JohnRiv37
Custom Elements
•Provides a way for authors to build their own
fully-featured DOM elements.
- <xc-tab>Your Wifi</xc-tab>
38. What Are Web Components?
Polymer-Powered Design Systems - @JohnRiv38
HTML Imports
39. What Are Web Components?
Polymer-Powered Design Systems - @JohnRiv39
HTML Imports
• Means to import custom elements
- <link rel="import" href="../xc-tab/xc-tab.html">
• Built-in deduplication
• Componetize the HTML, CSS & JavaScript
• Will be replaced by ES6 Modules
- import "../xc-tab/xc-tab.js"
40. What Are Web Components?
Polymer-Powered Design Systems - @JohnRiv40
Templates
41. What Are Web Components?
Polymer-Powered Design Systems - @JohnRiv41
• Used to declare fragments of HTML
- <template id="tab">
<div class="tab-content"></div>
</template>
• The element itself renders nothing
• Can be cloned and inserted in the document via
JavaScript, which will render the content
Templates
42. What Are Web Components?
Polymer-Powered Design Systems - @JohnRiv42
Shadow DOM
43. What Are Web Components?
Polymer-Powered Design Systems - @JohnRiv43
•Allows you to take a DOM subtree and
hide it from the document scope
•Hides CSS styles as well
•Common examples from HTML5 include:
<select>, <video>, & <input type="date">
Shadow DOM
46. How do I build my
Design System
using Polymer?
47. “A style guide is an artifact of design
process. A design system is a living,
funded product with a roadmap &
backlog, serving an ecosystem.”
- Nathan Curtis
Source: https://twitter.com/nathanacurtis/status/656829204235972608
49. “Establish a high-quality,
brand-aligned experience across
our product through human
guidance and internal tools.”
- Jina Anne
Source: https://medium.com/salesforce-ux/the-salesforce-team-model-for-scaling-a-design-system-d89c2a2d404b
Salesforce.com Design Systems Team Objective:
61. my-element.html:
<link rel="import"
href="bower_components/polymer/polymer-element.html">
<dom-module id="my-element">
<template>
<style>
/* My Element Styles */
</style>
<p>Shadow DOM is awesome</p>
</template>
<script>
class MyElement extends Polymer.Element {
static get is() { return 'my-element'; }
}
window.customElements.define(MyElement.is,
MyElement);
</script>
</dom-module>
index.html:
<!doctype html>
<html>
<head>
<title>Shadow DOM Demo</title>
<script
src="bower_components/webcomponentsjs/webcomponent
s-loader.js"></script>
<link rel="import" href="my-element.html">
<style>
/* Main Document Styles */
</style>
</head>
<body>
<my-element></my-element>
<p>Paragraph in the main document</p>
</body>
</html>
62. my-element.html:
<link rel="import"
href="bower_components/polymer/polymer-element.html">
<dom-module id="my-element">
<template>
<style>
/* My Element Styles */
</style>
<p>Shadow DOM is awesome</p>
</template>
<script>
class MyElement extends Polymer.Element {
static get is() { return 'my-element'; }
}
window.customElements.define(MyElement.is,
MyElement);
</script>
</dom-module>
index.html:
<!doctype html>
<html>
<head>
<title>Shadow DOM Demo</title>
<script
src="bower_components/webcomponentsjs/webcomponent
s-loader.js"></script>
<link rel="import" href="my-element.html">
<style>
/* Main Document Styles */
</style>
</head>
<body>
<my-element></my-element>
<p>Paragraph in the main document</p>
</body>
</html>
Load Polyfills (if needed)
63. my-element.html:
<link rel="import"
href="bower_components/polymer/polymer-element.html">
<dom-module id="my-element">
<template>
<style>
/* My Element Styles */
</style>
<p>Shadow DOM is awesome/p>
</template>
<script>
class MyElement extends Polymer.Element {
static get is() { return 'my-element'; }
}
window.customElements.define(MyElement.is,
MyElement);
</script>
</dom-module>
index.html:
<!doctype html>
<html>
<head>
<title>Shadow DOM Demo</title>
<script
src="bower_components/webcomponentsjs/webcomponent
s-loader.js"></script>
<link rel="import" href="my-element.html">
<style>
/* Main Document Styles */
</style>
</head>
<body>
<my-element></my-element>
<p>Paragraph in the main document</p>
</body>
</html>
Import my-element.html
64. my-element.html:
<link rel="import"
href="bower_components/polymer/polymer-element.html">
<dom-module id="my-element">
<template>
<style>
/* My Element Styles */
</style>
<p>Shadow DOM is awesome</p>
</template>
<script>
class MyElement extends Polymer.Element {
static get is() { return 'my-element'; }
}
window.customElements.define(MyElement.is,
MyElement);
</script>
</dom-module>
index.html:
<!doctype html>
<html>
<head>
<title>Shadow DOM Demo</title>
<script
src="bower_components/webcomponentsjs/webcomponent
s-loader.js"></script>
<link rel="import" href="my-element.html">
<style>
/* Main Document Styles */
</style>
</head>
<body>
<my-element></my-element>
<p>Paragraph in the main document</p>
</body>
</html>
Styles we’ll be modifying
65. index.html:
<!doctype html>
<html>
<head>
<title>Shadow DOM Demo</title>
<script
src="bower_components/webcomponentsjs/webcomponent
s-loader.js"></script>
<link rel="import" href="my-element.html">
<style>
/* Main Document Styles */
</style>
</head>
<body>
<my-element></my-element>
<p>Paragraph in the main document</p>
</body>
</html>
my-element.html:
<link rel="import"
href="bower_components/polymer/polymer-element.html">
<dom-module id="my-element">
<template>
<style>
/* My Element Styles */
</style>
<p>Shadow DOM is awesome</p>
</template>
<script>
class MyElement extends Polymer.Element {
static get is() { return 'my-element'; }
}
window.customElements.define(MyElement.is,
MyElement);
</script>
</dom-module>
Body contains <my-element> & <p>
66. my-element.html:
<link rel="import"
href="bower_components/polymer/polymer-element.html">
<dom-module id="my-element">
<template>
<style>
/* My Element Styles */
</style>
<p>Shadow DOM is awesome</p>
</template>
<script>
class MyElement extends Polymer.Element {
static get is() { return 'my-element'; }
}
window.customElements.define(MyElement.is,
MyElement);
</script>
</dom-module>
index.html:
<!doctype html>
<html>
<head>
<title>Shadow DOM Demo</title>
<script
src="bower_components/webcomponentsjs/webcomponent
s-loader.js"></script>
<link rel="import" href="my-element.html">
<style>
/* Main Document Styles */
</style>
</head>
<body>
<my-element></my-element>
<p>Paragraph in the main document</p>
</body>
</html>
Flattened DOM Tree:
<body>
<my-element>
#shadow-root (open)
<style>...</style>
<p>Shadow DOM is awesome</p>
</my-element>
<p>Paragraph in the main document</p>
</body>
67. Rendered Result:
Shadow DOM is awesome
Paragraph in the main document
my-element.html:
<style>
p {
border: 3px solid #f60;
}
</style>
index.html:
<style>
p {
background-color: #9cf;
}
</style>
68. Rendered Result:
Shadow DOM is awesome
Paragraph in the main document
my-element.html:
<style>
:host {
}
p {
border: 3px solid #f60;
}
</style>
:host selector
69. Rendered Result:
Shadow DOM is awesome
Paragraph in the main document
my-element.html:
<style>
:host {
}
p {
border: 3px solid #f60;
}
</style>
Flattened DOM Tree:
<body>
<my-element>
#shadow-root (open)
<style>...</style>
<p>Shadow DOM is awesome</p>
</my-element>
<p>Paragraph in the main document</p>
</body>
70. Rendered Result:
Shadow DOM is awesome
Paragraph in the main document
my-element.html:
<style>
:host {
outline: 3px dashed blue;
}
p {
border: 3px solid #f60;
}
</style>
71. Rendered Result:
Shadow DOM is awesome
Paragraph in the main document
my-element.html:
<style>
:host {
outline: 3px dashed blue;
display: block;
}
p {
border: 3px solid #f60;
}
</style>
72. Rendered Result:
Shadow DOM is awesome
Paragraph in the main document
my-element.html:
<style>
:host {
outline: 3px dashed blue;
display: block;
contain: content;
}
p {
border: 3px solid #f60;
}
</style>
See https://developers.google.com/web/updates/2016/06/css-containment for more information on contain
73. Rendered Result:
Shadow DOM is awesome
Paragraph in the main document
my-element.html:
<style>
:host {
outline: 3px dashed blue;
display: block;
contain: content;
}
p {
border: 3px solid #f60;
margin: 0;
}
</style>
See https://developers.google.com/web/updates/2016/06/css-containment for more information on contain
74. Rendered Result:
Shadow DOM is awesome
Paragraph in the main document
my-element.html:
<style>
:host {
outline: 3px dashed blue;
display: block;
contain: content;
}
:host([disabled]) {
outline-color: #ccc;
}
:host([disabled]) > p {
border-color: #ccc;
} ...
</style>
75. Rendered Result:
Shadow DOM is awesome
Paragraph in the main document
my-element.html:
<style>
:host {
outline: 3px dashed blue;
display: block;
contain: content;
}
:host([disabled]) {
outline-color: #ccc;
}
:host([disabled]) > p {
border-color: #ccc;
} ...
</style>
index.html:
<my-element></my-element>
<p>Paragraph in the main
document</p>
76. Rendered Result:
Shadow DOM is awesome
Paragraph in the main document
my-element.html:
<style>
:host {
outline: 3px dashed blue;
display: block;
contain: content;
}
:host([disabled]) {
outline-color: #ccc;
}
:host([disabled]) > p {
border-color: #ccc;
} ...
</style>
index.html:
<my-element disabled></my-element>
<p>Paragraph in the main
document</p>
77. Rendered Result:
Shadow DOM is awesome
Paragraph in the main document
my-element.html:
<style>
:host {
outline: 3px dashed blue;
display: block;
contain: content;
}
:host([disabled]) {
outline-color: #ccc;
}
:host([disabled]) > p {
border-color: #ccc;
} ...
</style>
index.html:
<my-element></my-element>
<p>Paragraph in the main
document</p>
78. Rendered Result:
Shadow DOM is awesome
Paragraph in the main document
my-element.html:
<style>
:host {
outline: 3px dashed blue;
display: block;
contain: content;
}
p {
border: 3px solid #f60;
margin: 0;
}
</style>
index.html:
<my-element></my-element>
<p>Paragraph in the main
document</p>
79. Rendered Result:
Shadow DOM is awesome
Paragraph in the main document
my-element.html:
<style>
:host {
outline: 3px dashed blue;
display: block;
contain: content;
}
p {
border: 3px solid #f60;
margin: 0;
}
</style>
index.html:
<style>
p { background-color: #9cf; }
</style>
80. Rendered Result:
Shadow DOM is awesome
Paragraph in the main document
index.html:
<style>
p { background-color: #9cf; }
my-element { outline-color: red; }
</style>
my-element.html:
<style>
:host {
outline: 3px dashed blue;
display: block;
contain: content;
}
p {
border: 3px solid #f60;
margin: 0;
}
</style>
81. Rendered Result:
Shadow DOM is awesome
Paragraph in the main document
index.html:
<style>
p { background-color: #9cf; }
my-element { outline-color: red; }
my-element p {
border-color: blue;
}
</style>
my-element.html:
<style>
:host {
outline: 3px dashed blue;
display: block;
contain: content;
}
p {
border: 3px solid #f60;
margin: 0;
}
</style>
82. Rendered Result:
Shadow DOM is awesome
Paragraph in the main document
my-element.html:
<style>
:host {
outline: 3px dashed blue;
display: block;
contain: content;
}
p {
border: 3px solid #f60;
margin: 0;
}
</style>
index.html:
<style>
p { background-color: #9cf; }
</style>
83. Rendered Result:
Shadow DOM is awesome
Paragraph in the main document
my-element.html:
<style>
:host {
outline: 3px dashed blue;
display: block;
contain: content;
}
p {
border: 3px solid #f60;
margin: 0;
}
</style>
index.html:
<my-element></my-element>
<p>Paragraph in the main
document</p>
84. Rendered Result:
Shadow DOM is awesome
Paragraph in the main document
my-element.html:
<style>
:host {
outline: 3px dashed blue;
display: block;
contain: content;
}
p {
border: 3px solid #f60;
margin: 0;
}
</style>
index.html:
<my-element>
<ul>
</ul>
</my-element>
<p>Paragraph in the main
document</p>
85. Rendered Result:
Shadow DOM is awesome
Paragraph in the main document
my-element.html:
<style>
:host {
outline: 3px dashed blue;
display: block;
contain: content;
}
p {
border: 3px solid #f60;
margin: 0;
}
</style>
index.html:
<my-element>
<ul>
<li>This is Light DOM</li>
<li>It needs a slot</li>
</ul>
</my-element>
<p>Paragraph in the main
86. my-element.html:
<template>
<style> ... </style>
<p>Shadow DOM is awesome</p>
</template>
Rendered Result:
Shadow DOM is awesome
Paragraph in the main document
index.html:
<my-element>
<ul>
<li>This is Light DOM</li>
<li>It needs a slot</li>
</ul>
</my-element>
<p>Paragraph in the main
88. my-element.html:
<template>
<style> ... </style>
<p>Shadow DOM is awesome</p>
<slot></slot>
</template>
Rendered Result:
Shadow DOM is awesome
• This is Light DOM
• It needs a slot
Paragraph in the main document
Flattened DOM Tree:
<body>
<my-element>
#shadow-root (open)
<style>...</style>
<p>Shadow DOM is awesome</p>
<slot>
<ul>
<li>This is Light DOM</li>
<li>It needs a slot</li>
</ul>
</slot>
</my-element> ...
89. my-element.html:
<template>
<style> ... </style>
<p>Shadow DOM is awesome</p>
<slot></slot>
</template>
Rendered Result:
Shadow DOM is awesome
• This is Light DOM
• It needs a slot
Paragraph in the main document
Flattened DOM Tree:
<body>
<my-element>
#shadow-root (open)
<style>...</style>
<p>Shadow DOM is awesome</p>
<slot>
<ul>
<li>This is Light DOM</li>
<li>It needs a slot</li>
</ul>
</slot>
</my-element> ...
98. my-element.html:
<template>
<style>
...
::slotted(ul) {
margin: 0;
color: blue;
}
</style>
<p>Shadow DOM is awesome</p>
<slot></slot>
</template>
Rendered Result:
Shadow DOM is awesome
• This is Light DOM
• It needs a slot
Paragraph in the main document
index.html:
<style>
p { background-color: #9cf; }
ul { color: red; }
</style>
99. my-element.html:
<template>
<style>
...
::slotted(ul) {
margin: 0;
color: blue;
}
</style>
<p>Shadow DOM is awesome</p>
<slot></slot>
</template>
Rendered Result:
Shadow DOM is awesome
• This is Light DOM
• It needs a slot
Paragraph in the main document
index.html:
<style>
p { background-color: #9cf; }
</style>
101. my-element.html:
<template>
<style>
:host {
outline: 3px dashed blue;
display: block;
contain: content;
}
p {
border: 3px solid #f60;
margin: 0;
}
::slotted(ul) { ...
Rendered Result:
Shadow DOM is awesome
• This is Light DOM
• It needs a slot
Paragraph in the main document
index.html:
<style>
p { background-color: #9cf; }
</style>
102. my-element.html:
<template>
<style>
:host {
outline: 3px dashed blue;
display: block;
contain: content;
}
p {
border: 3px solid #f60;
margin: 0;
}
::slotted(ul) { ...
Rendered Result:
Shadow DOM is awesome
• This is Light DOM
• It needs a slot
Paragraph in the main document
index.html:
<style>
body { color: green;
font-family: Calibri; }
p { background-color: #9cf; }
103. my-element.html:
<template>
<style>
:host {
outline: 3px dashed blue;
display: block;
contain: content;
color: initial;
}
p {
border: 3px solid #f60;
margin: 0;
}
::slotted(ul) { ...
Rendered Result:
Shadow DOM is awesome
• This is Light DOM
• It needs a slot
Paragraph in the main document
index.html:
<style>
body { color: green;
font-family: Calibri; }
p { background-color: #9cf; }
104. my-element.html:
<template>
<style>
:host {
outline: 3px dashed blue;
display: block;
contain: content;
all: initial;
}
p {
border: 3px solid #f60;
margin: 0;
}
::slotted(ul) { ...
Rendered Result:
Shadow DOM is awesome
• This is Light DOM
• It needs a slot
Paragraph in the main document
index.html:
<style>
body { color: green;
font-family: Calibri; }
p { background-color: #9cf; }
107. CSS Custom Properties
Basic usage:
<style>
html {
/* Define a Custom Property */
--body-text-color: gray;
}
p {
/* Use a Custom Property */
color: var(--body-text-color);
}
</style>
Polymer-Powered Design Systems107
108. CSS Custom Properties
Basic usage:
<style>
html {
/* Define a Custom Property */
--body-text-color: gray;
}
p {
/* Use a Custom Property with a fallback value */
color: var(--body-text-color, navy);
}
</style>
Polymer-Powered Design Systems108
109. CSS Custom Properties
Basic usage:
<style>
html {
/* Define a Custom Property */
--body-text-color: gray;
}
p {
/* Use a Custom Property with multiple fallback values */
color: var(--body-text-color, var(--p-text-color, navy));
}
</style>
Polymer-Powered Design Systems109
110. my-element.html:
<style>
:host {
outline: 3px dashed blue;
display: block;
contain: content;
}
p {
border: 3px solid #f60;
margin: 0;
}
::slotted(ul) {
margin: 0; ...
Rendered Result:
Shadow DOM is awesome
• This is Light DOM
• It needs a slot
Paragraph in the main document
index.html:
<style>
p { background-color: #9cf; }
</style>
111. my-element.html:
<style>
:host {
outline: 3px dashed blue;
display: block;
contain: content;
}
p {
border: 3px solid
var(--my-element-border-color,
#f60);
margin: 0;
}
::slotted(ul) {
Rendered Result:
Shadow DOM is awesome
• This is Light DOM
• It needs a slot
Paragraph in the main document
index.html:
<style>
p { background-color: #9cf; }
</style>
112. my-element.html:
<style>
:host {
outline: 3px dashed blue;
display: block;
contain: content;
}
p {
border: 3px solid
var(--my-element-border-color,
#f60);
margin: 0;
}
::slotted(ul) {
Rendered Result:
Shadow DOM is awesome
• This is Light DOM
• It needs a slot
Paragraph in the main document
index.html:
<style>
html { --my-element-border-color:
purple; }
p { background-color: #9cf; }
113. • Name colors: --xc-blue-sky: #0272B6;
• Set variables for usage: --xc-link-color: var(--xc-blue-sky);
• Useful to name Custom Property hooks in the format of
--element-property: var(--my-element-border-color, #f60);
• Besides colors, gaps and/or padding factors are useful:
--xc-main-gap: 16px; --xc-large-gap: 24px;
padding: var(--xc-main-gap); padding: calc(1.5*var(--xc-main-gap));
CSS Custom Properties Tips
Polymer-Powered Design Systems113
120. my-element.html:
<link rel="import"
href="bower_components/polymer/
polymer.html">
...
<style> ...
p {
border: 3px solid
var(--my-element-border-color,
#f60);
margin: 0;
@apply --my-element-p;
} ...
Rendered Result:
Shadow DOM is awesome
• This is Light DOM
• It needs a slot
Paragraph in the main document
index.html:
<style>
html {
--my-element-border-color: purple; }
}
p { background-color: #9cf; }
...
</style>
121. my-element.html:
<link rel="import"
href="bower_components/polymer/
polymer.html">
...
<style> ...
p {
border: 3px solid
var(--my-element-border-color,
#f60);
margin: 0;
@apply --my-element-p;
} ...
Rendered Result:
Shadow DOM is awesome
• This is Light DOM
• It needs a slot
Paragraph in the main document
index.html:
<style>
html {
--my-element-p {
background: red;
font-style: italic;
}; ...
} ... </style>
122. my-element.html:
<link rel="import"
href="bower_components/polymer/
polymer.html">
...
<style> ...
p {
border: 3px solid
var(--my-element-border-color,
#f60);
margin: 0;
@apply --my-element-p;
} ...
Rendered Result:
Shadow DOM is awesome
• This is Light DOM
• It needs a slot
Paragraph in the main document
index.html:
<custom-style> <style>
html {
--my-element-p: {
background: red;
font-style: italic;
}; ...
} ... </style> </custom-style>
123. my-element.html:
<link rel="import"
href="bower_components/polymer/
polymer.html">
...
<style> ...
p {
border: 3px solid
var(--my-element-border-color,
#f60);
margin: 0;
@apply --my-element-p;
} ...
Rendered Result:
Shadow DOM is awesome
• This is Light DOM
• It needs a slot
Paragraph in the main document
index.html:
<custom-style> <style>
html {
--my-element-p: {
background: red;
font-style: italic;
}; ...
} ... </style> </custom-style>
Style in my-element.html after shim is applied:
<style>
p {
border: 3px solid var(--my-element-border-color, #f60);
margin: 0;
background: var(--my-element-p_-_background);
font-style: var(--my-element-p_-_font-style);
}
</style>
124. my-element.html:
<link rel="import"
href="bower_components/polymer/
polymer.html">
...
<style> ...
p {
border: 3px solid
var(--my-element-border-color,
#f60);
margin: 0;
@apply --my-element-p;
} ...
Rendered Result:
Shadow DOM is awesome
• This is Light DOM
• It needs a slot
Paragraph in the main document
index.html:
<custom-style> <style>
html {
--my-element-p: {
background: red;
font-style: italic;
}; ...
} ... </style> </custom-style>
Style in my-element.html after shim is applied:
<style>
p {
border: 3px solid var(--my-element-border-color, #f60);
margin: 0;
background: var(--my-element-p_-_background);
font-style: var(--my-element-p_-_font-style);
}
</style>
125. my-element.html:
<link rel="import"
href="bower_components/polymer/
polymer.html">
...
<style> ...
p {
border: 3px solid
var(--my-element-border-color,
#f60);
margin: 0;
@apply --my-element-p;
} ...
Rendered Result:
Shadow DOM is awesome
• This is Light DOM
• It needs a slot
Paragraph in the main document
index.html:
<custom-style> <style>
html {
--my-element-p: {
background: red;
font-style: italic;
}; ...
} ... </style> </custom-style>
Style in my-element.html after shim is applied:
<style>
p {
border: 3px solid var(--my-element-border-color, #f60);
margin: 0;
background: var(--my-element-p_-_background);
font-style: var(--my-element-p_-_font-style);
}
</style>
126. my-element.html:
<link rel="import"
href="bower_components/polymer/
polymer.html">
...
<style> ...
p {
border: 3px solid
var(--my-element-border-color,
#f60);
margin: 0;
@apply --my-element-p;
} ...
Rendered Result:
Shadow DOM is awesome
• This is Light DOM
• It needs a slot
Paragraph in the main document
index.html:
<custom-style> <style>
html {
--my-element-p: {
background: red;
font-style: italic;
}; ...
} ... </style> </custom-style>
Style in my-element.html after shim is applied:
<style>
p {
border: 3px solid var(--my-element-border-color, #f60);
margin: 0;
background: var(--my-element-p_-_background);
font-style: var(--my-element-p_-_font-style);
}
</style>
Style in index.html after shim is applied:
<custom-style> <style>
html {
--my-element-border-color: purple;
--my-element-p_-_background: red;
--my-element-p_-_font-style: italic;
}
</style> </custom-style>
127. my-element.html:
<link rel="import"
href="bower_components/polymer/
polymer.html">
...
<style> ...
p {
border: 3px solid
var(--my-element-border-color,
#f60);
margin: 0;
@apply --my-element-p;
} ...
Rendered Result:
Shadow DOM is awesome
• This is Light DOM
• It needs a slot
Paragraph in the main document
index.html:
<custom-style> <style>
html {
--my-element-p: {
background: red;
font-style: italic;
}; ...
} ... </style> </custom-style>
Style in my-element.html after shim is applied:
<style>
p {
border: 3px solid var(--my-element-border-color, #f60);
margin: 0;
background: var(--my-element-p_-_background);
font-style: var(--my-element-p_-_font-style);
}
</style>
Style in index.html after shim is applied:
<custom-style> <style>
html {
--my-element-border-color: purple;
--my-element-p_-_background: red;
--my-element-p_-_font-style: italic;
}
</style> </custom-style>
128. my-element.html:
<link rel="import"
href="bower_components/polymer/
polymer.html">
...
<style> ...
p {
border: 3px solid
var(--my-element-border-color,
#f60);
margin: 0;
@apply --my-element-p;
} ...
Rendered Result:
Shadow DOM is awesome
• This is Light DOM
• It needs a slot
Paragraph in the main document
index.html:
<custom-style> <style>
html {
--my-element-p: {
background: red;
font-style: italic;
}; ...
} ... </style> </custom-style>
Style in my-element.html after shim is applied:
<style>
p {
border: 3px solid var(--my-element-border-color, #f60);
margin: 0;
background: var(--my-element-p_-_background);
font-style: var(--my-element-p_-_font-style);
}
</style>
Style in index.html after shim is applied:
<custom-style> <style>
html {
--my-element-border-color: purple;
--my-element-p_-_background: red;
--my-element-p_-_font-style: italic;
}
</style> </custom-style>
129. • Used for setting styles in the main document, either:
- Declared directly in the main document, or
- Hoisted to the main document from an import
• When would you want to include them in an import?
- @font-face rules
- Theming (declaring common variables & mixins)
• <custom-style> & @apply can be loaded on their own via
ShadyCSS (see https://github.com/webcomponents/shadycss)
More <custom-style> notes
Polymer-Powered Design Systems129
130. • This warning is unavoidable when using <custom-style>:
• If you’re using at least Polymer 1.10.1 or 2.1.1, you’re good
More <custom-style> notes
Polymer-Powered Design Systems130
131. • Style Modules are Polymer’s way of sharing styles among
Polymer Components
• The styles are actually copied into the Shadow Root of the
component they are included in
- So only include what you actually need
• Great way of sharing form element styles like buttons
Another way to share styles: Style Modules
Polymer-Powered Design Systems131
139. ShadyCSS Shim Limitations
• ::slotted needs a selector before it (such as :host)
• External stylesheets within a shadow root cannot be shimmed
- So no <link rel="stylesheet"> or @import
• Avoid dynamic changes, including:
- Changing a custom property value
- Adding styles after the scoping shim is executed
Polymer-Powered Design Systems139
Additional Details: https://github.com/webcomponents/shadycss#limitations
141. Documenting Your Polymer Code
• Document with JSDoc syntax - usejsdoc.org
• Create a page that imports & includes iron-component-page
• Generate the docs and load your page:
$ npm i -g polymer-cli bower
$ polymer analyze > analysis.json
$ polymer serve --open
Polymer-Powered Design Systems141
Additional Details: https://github.com/PolymerElements/iron-component-page
142.
143. <!--
Material design:
[Tabs](https://www.google.com/design/s
pec/components/tabs.html)
`paper-tabs` makes it easy to explore
and switch between different views or
functional aspects of
an app, or to browse categorized data
sets.
Use `selected` property to get or set
the selected tab.
Example:
<paper-tabs selected="0">
<paper-tab>TAB 1</paper-tab>
<paper-tab>TAB 2</paper-tab>
<paper-tab>TAB 3</paper-tab>
</paper-tabs>
144.
145. <!--
### Styling
The following custom properties and
mixins are available for styling:
Custom property | Description |
Default
----------------|-------------|-------
---
`--paper-tabs-selection-bar-color` |
Color for the selection bar | `--
paper-yellow-a100`
`--paper-tabs-selection-bar` | Mixin
applied to the selection bar | `{}`
`--paper-tabs` | Mixin applied to the
tabs | `{}`
`--paper-tabs-content` | Mixin applied
to the content container of tabs |
`{}`
`--paper-tabs-container` | Mixin
applied to the layout container of
146.
147. /**
* If true, the tabs are aligned
to bottom (the selection bar
appears at the top).
*/
alignBottom: {
type: Boolean,
value: false
},
/**
* If true, tabs are
automatically selected when
focused using the
* keyboard.
*/
autoselect: {
type: Boolean,
value: false
},
158. Using Web Components
• Import the component
- <link rel="import" href="https://your-web-component-
cdn.com/iron-pages/iron-pages.html">
• Use your custom element as a normal HTML tag
- <iron-pages>
<div>Page 1 content</div>
<div>Page 2 content</div>
</iron-pages>
Polymer-Powered Design Systems - @JohnRiv158
162. Polymer-Powered Design Systems
• Have a team of designers & developers
responsible for your design system
• Polymer & Web Components are a great way to
build reusable components that work across
multiple frameworks
• Don’t forget your colons & semicolons when
defining Polymer CSS Mixins
• Embrace Demo Driven Development
Polymer-Powered Design Systems - @JohnRiv162
163. Useful Links
•WebComponents.org - webcomponents.org
•Polymer Website - polymer-project.org
•Polymer Slack - polymer-slack.herokuapp.com
•Polymer 2.x Cheat Sheet - https://meowni.ca/posts/polymer-2-cheatsheet/
•How to use Polymer with Webpack - http://robdodson.me/how-to-use-polymer-with-webpack/
•Hands-on with the Polymer 3.0 preview - https://www.polymer-project.org/blog/2017-08-23-hands-
on-30-preview
•Custom Elements Everywhere - https://custom-elements-everywhere.com/
•Polycasts on YouTube -
https://www.youtube.com/playlist?list=PLOU2XLYxmsII5c3Mgw6fNYCzaWrsM3sMN
•2017 Polymer Summit videos on YouTube -
https://www.youtube.com/playlist?list=PLNYkxOF6rcIDP0PqVaJxqNWwIgvoEPzJi
•End-to-End Polymer Apps - 2017 Chrome Dev Summit video - https://youtu.be/Wu2GCRkDecI
•2017 Google I/O Polymer videos on YouTube -
https://www.youtube.com/playlist?list=PL_c6rbXV248du6m1VJABo32mP7sXWVb4m
Polymer-Powered Design Systems - @JohnRiv163