Improving pattern libraries, with Polymer.
Sam Beckham
@samdbeckham
http://nodivide.us
https://frontendne.co.uk
WTF is a pattern library?
A coded
style guide
A collection of code examples
A bit like bootstrap
A separation of concerns
(Between the front and back end)
Pretty
Freaking
Awesome.
Copy this
<ul class="pagination">
<li>1</li>
<li class="pagination__current-page">2</li>
<li>3</li>
<li>4</li>
<li>5</li>
</ul>
Get this
What's the beef then?
Lots of copying and pasting
<ul>
<li class="field__location">
<span class="field__location__name">Location</span>
<div class="field__location__map">
<div class="location__loading-indicator">
<svg viewbox="0 0 100 100" class="icon icon__logomark animation animation--infinite animation__spin">
<use xlink:href="/resources/images/sprite/icon-sprite.svg#icon__logomark"></use>
</svg>
</div>
</div>
<div class="field__location__search">
<input type="search" value="" placeholder="Enter a postcode or a place." />
</div>
<ul class="form-fields grid">
<li class="column column__6-of-12">
<label for="lat">Latitude</label>
<input type="text" pattern="-?[0-9]{0,2}\.?[0-9]*" id="lat" name="lat" class="field__location__lat" value="54.981308">
</li>
<li class="column column__6-of-12">
<label for="lon">Longitude</label>
<input type="text" pattern="-?[0-9]{0,3}\.?[0-9]*" id="lon" name="lon" class="field__location__lon" value="-1.608489">
</li>
</ul>
</li>
</ul>
Code can be hard to understand
<ul>
<li class="field__location">
<span class="field__location__name">Location</span>
<div class="field__location__map">
<div class="location__loading-indicator">
<svg viewbox="0 0 100 100" class="icon icon__logomark animation animation--infinite animation__spin">
<use xlink:href="/resources/images/sprite/icon-sprite.svg#icon__logomark"></use>
</svg>
</div>
</div>
<div class="field__location__search">
<input type="search" value="" placeholder="Enter a postcode or a place." />
</div>
<ul class="form-fields grid">
<li class="column column__6-of-12">
<label for="lat">Latitude</label>
<input type="text" pattern="-?[0-9]{0,2}\.?[0-9]*" id="lat" name="lat" class="field__location__lat" value="54.981308">
</li>
<li class="column column__6-of-12">
<label for="lon">Longitude</label>
<input type="text" pattern="-?[0-9]{0,3}\.?[0-9]*" id="lon" name="lon" class="field__location__lon" value="-1.608489">
</li>
</ul>
</li>
</ul>
They're difficult to maintain
<div class="pagination">
<a href="#" class="button button--disabled pagination__paddle" disabled>< Prev</a>
<input class="pagination__page" type="text" inputmode="number" pattern="[0-9]+" max="52" value="1">
<span class="pagination__limit">52</span>
<a href="#" class="button pagination__paddle">Next ></a>
</div>
Pagination
Component
<ul class="pagination">
<li>1</li>
<li>2</li>
<li>3</li>
<li class="pagination__current-page">4</li>
<li>5</li>
<li>6</li>
<li>7</li>
</ul>
Pagination
Component
Markup changes funk you up
A separation of concerns?
Not quite
It's good…
…but it's not right
Enter, Polymer
WTF is Polymer?
Web component framework
A collection of Web components
WTF are web components?
"Web Components are a set of standards currently being produced by Google engineers as a W3C specification that allow for the creation of reusable widgets or components in web documents and web applications. The intention behind them is to bring component-based software engineering to the World Wide Web. The components model allows for encapsulation and interoperability of individual HTML elements."
tl:dr;
Create your own HTML elements
Contain
your styles within them
Utilise
lifecycle callbacks
A separation of concerns
Pretty
Freaking
Awesome.
Let's mix them together
<div class="pagination">
<a href="#" class="button button--disabled pagination__paddle" disabled>< Prev</a>
<input class="pagination__page" type="text" inputmode="number" pattern="[0-9]+" max="52" value="1">
<span class="pagination__limit">52</span>
<a href="#" class="button pagination__paddle">Next ></a>
</div>
Pagination
Component
<my-pagination></my-pagination>
Pagination
Component
<my-pagination
currentpage="1"
totalpages="52">
</my-pagination>
Pagination
Component
How it's made
<link
rel="import"
href=".../polymer.html">
Import Polymer
<link
rel="import"
href=".../polymer.html">
<polymer-element
name="my-pagination">
</polymer-element>
Polymer Element
<link
rel="import"
href=".../polymer.html">
<polymer-element
name="my-pagination"
attributes="totalpages currentpage">
</polymer-element>
Element Attributes
<link
rel="import"
href=".../polymer.html">
<polymer-element
name="my-pagination"
attributes="totalpages currentpage">
<template>
<!-- Element markup goes here -->
</template>
</polymer-element>
Element Template
<link
rel="import"
href=".../polymer.html">
<polymer-element
name="my-pagination"
attributes="totalpages currentpage">
<template>
<!-- Element markup goes here -->
</template>
<script>
Polymer();
</script>
</polymer-element>
Scripts
<link
rel="import"
href=".../polymer.html">
<polymer-element
name="my-pagination"
attributes="totalpages currentpage"
noscript>
<template>
<!-- Element markup goes here -->
</template>
</polymer-element>
Noscript
<template>
<!-- Element markup goes here -->
</template>
Template
<template>
<div class="pagination">
<a class="pagination__paddle">Prev</a>
<input
class="pagination__page"
type="text"
max="52"
value="1">
<span class="pagination__limit">52</span>
<a href="#" class="pagination__paddle">Next</a>
</div>
</template>
Static HTML
<template>
<link rel="stylesheet" href="my-pagination.css">
<div class="pagination">
<a class="pagination__paddle">Prev</a>
<input
class="pagination__page"
type="text"
max="52"
value="1">
<span class="pagination__limit">52</span>
<a href="#" class="pagination__paddle">Next</a>
</div>
</template>
Styles
<template>
<link rel="stylesheet" href="my-pagination.css">
<div class="pagination">
<a class="pagination__paddle">Prev</a>
<input
class="pagination__page"
type="text"
max="{{ totalpages }}"
value="{{ currentpage }}">
<span class="pagination__limit">{{ totalpages }}</span>
<a href="#" class="pagination__paddle">Next</a>
</div>
</template>
Attribute injection
<template>
...
<template
if="{{ currentpage == 1 }}">
<a class="pagination__paddle disabled">Prev</a>
</template>
<template
if="{{ currentpage != 1 }}">
<a class="pagination__paddle">Prev</a>
</template>
...
</template>
Inline logic
<html>
<head>
<link
rel="import"
href=".../my-pagination.html">
</head>
<body>
<!-- Content goes here -->
</body>
</html>
Import it
<html>
<head>
<link
rel="import"
href=".../my-pagination.html">
</head>
<body>
<my-pagination
currentpage="1"
totalpages="52">
</my-pagination>
</body>
</html>
Use it
That's it
What does this solve?
Lots of copying and pasting
<ul>
<li class="field__location">
<span class="field__location__name">Location</span>
<div class="field__location__map">
<div class="location__loading-indicator">
<svg viewbox="0 0 100 100" class="icon icon__logomark animation animation--infinite animation__spin">
<use xlink:href="/resources/images/sprite/icon-sprite.svg#icon__logomark"></use>
</svg>
</div>
</div>
<div class="field__location__search">
<input type="search" value="" placeholder="Enter a postcode or a place." />
</div>
<ul class="form-fields grid">
<li class="column column__6-of-12">
<label for="lat">Latitude</label>
<input type="text" pattern="-?[0-9]{0,2}\.?[0-9]*" id="lat" name="lat" class="field__location__lat" value="54.981308">
</li>
<li class="column column__6-of-12">
<label for="lon">Longitude</label>
<input type="text" pattern="-?[0-9]{0,3}\.?[0-9]*" id="lon" name="lon" class="field__location__lon" value="-1.608489">
</li>
</ul>
</li>
</ul>
<location-field
lon="-1.608489"
lat="54.981308">
</location-field>
Some copying and pasting
Code can be hard to understand
<ul>
<li class="field__location">
<span class="field__location__name">Location</span>
<div class="field__location__map">
<div class="location__loading-indicator">
<svg viewbox="0 0 100 100" class="icon icon__logomark animation animation--infinite animation__spin">
<use xlink:href="/resources/images/sprite/icon-sprite.svg#icon__logomark"></use>
</svg>
</div>
</div>
<div class="field__location__search">
<input type="search" value="" placeholder="Enter a postcode or a place." />
</div>
<ul class="form-fields grid">
<li class="column column__6-of-12">
<label for="lat">Latitude</label>
<input type="text" pattern="-?[0-9]{0,2}\.?[0-9]*" id="lat" name="lat" class="field__location__lat" value="54.981308">
</li>
<li class="column column__6-of-12">
<label for="lon">Longitude</label>
<input type="text" pattern="-?[0-9]{0,3}\.?[0-9]*" id="lon" name="lon" class="field__location__lon" value="-1.608489">
</li>
</ul>
</li>
</ul>
<location-field
lon="-1.608489"
lat="54.981308">
</location-field>
Code is super easy to understand
It's difficult to maintain
<my-pagination
totalpages="7"
currentpage="4">
</my-pagination>
Pagination
Component
<my-pagination
currentpage="1"
totalpages="52">
</my-pagination>
Pagination
Component
It's easy to maintain
A TRUE separation of concerns
Pretty
Freaking
Awesome.
Can I use
it now?
YES!
(kind of)
Polyfills
Use it where you can
Things can only get better
Moar
Stuff
https://github.com/samdbeckham/polymer-pattern-library-example
http://polymer-project.org
http://webcomponents.org
http://reddit.com/r/polymerjs
Thanks!
Sam Beckham
@samdbeckham
Improving pattern libraries, with Polymer.
By Sam Beckham
Improving pattern libraries, with Polymer.
Pattern libraries, style guides, component libraries; whatever you call them, they're awesome. They've changed the way we think about developing apps and websites. Their component-based design allows us to prototype templates faster, and update existing templates easier. But with all this power, comes great responsibility. Pattern libraries are notoriously difficult to maintain. The smallest change to the library could mean updating countless files on your app. As a result, it becomes tempting to issue 'quick fixes' on your app and leave the pattern library to fall out of date. Enter web components - the solution to our problems. With their component-driven approach, they're the perfect fit for pattern libraries. How do we combine the two? Well, let me show you.
- 2,236