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,106