Welcome to BrownBag!

Ahem.. is this thing on??

Building a Component Library

What's the point of this talk?

• Explain the what and why of component libs

• Explain the process of building a library

• Encourage you build and publish your own libs

What is a component library?

• a collection of reusable and extensible UI bits

Some Examples

• Usually more than standalone component libs

Why Build My Own?

• Keep UI consistent across multiple applications

• Build once, reuse often

• Leverage predictable and reliable UI

• Version control with npm

• Strengthen your frontend skillset 💪

Why Build My Own?

meme credit here

Why React?

• Component-based structure

• Testability

• Portability

Initial Setup

• Initialize git and npm

• Dependency management and .npmignore

• Use Babel to compile ES2015 (and JSX)

• Add linting and testing

• Add helpful documentation & a CoC

 

Want more details?

I wrote an article with detailed steps on this setup here.

I also gave a talk on publishing to npm, & the slides are here.

Script Overview

  // package.json

  ...
  "main": "build/index.js",
  ...
  "scripts": {
    "build": "babel lib -d build",
    "build:watch": "babel lib -w -d build",
    "lint": "eslint lib/**; exit 0",
    "lint:watch": "esw -w lib/**",
    "prepublish": "npm run build",
    "test": "mocha --compilers js:babel-core/register ./test/**/*.spec.js",
    "test:watch": "npm test -- --watch"
  },
  ...

File Structure

Using Styled Components 💅

• Bundles our CSS with our JS

• Write real CSS 🎊

• Styles are predictable and reliable

• Users don't need to install additional deps

• Server-side rendering (if needed)

• Theming becomes a lot simpler

 

Looking for other alternatives?

Check out Glamor & Glamorous!

Also check out Aphrodite & Radium!

Applying Atomic Design

Want to know more?

You can read more or buy Brad Frost's book here.

A Few Modifications

• Atoms => Elements

(spans, buttons, etc.)

 

 

 

• Molecules => Components

(search field, dropdown, etc.)

 

 

 

Organisms, Templates, & Pages

Adding a Button

import styled from 'styled-components';

const Button = styled.button`
  background: #1FB6FF;
  border: none;
  border-radius: 2px;
  color: #FFFFFF;
  cursor: pointer;
  display: inline-block;
  font-size: 16px;
  line-height: 40px;
  font-weight: 200;
  margin: 8px 0;
  outline: none;
  padding: 0 12px;
  text-transform: uppercase;
  transition: all 300ms ease;
  &:hover {
    background: #009EEB;
  }
`;

export default Button;

Updating index.js

// lib/index.js

import Button from './elements/Button’;

module.exports = {
  Button,
};

Publish! ... right?

Well, it would be nice to test it locally first though...

Development Workflow

// from the root of your component library
$ npm link
// set up a playground app for testing our library

$ git clone git@github.com:alanbsmith/component-lib-playground.git
$ cd component-lib-playground
$ npm install

// link our local module
$ npm link name-of-your-lib

// fire up the app
$ npm run dev

Create a symlink of our module

Add a playground

Hot Updates

// from the root of your component library
$ npm run build:watch
// update our button color to purple

const Button = styled.button`
  background: #7E5BEF;
  ...
  &:hover {
    background: #592DEA;
  }
`;

Run `build:watch` script

Making an update to our lib

This is cool, but...

It would be nice if our users had more control

Things to think about

• Balancing convention and customization

• What use-cases to cover

• Where is our greatest need? (for internal use)

 

Add a Color Palette

// lib/styles/colors.js
module.exports = {
  white: '#FFFFFF',
  lightBlue: '#85D7FF',
  blue: '#1FB6FF',
  darkBlue: '#009EEB',
  lightPurple: '#A389F4',
  purple: '#7E5BEF',
  darkPurple: '#592DEA',
  lightPink: '#FF7CE5',
  pink: '#FF49DB',
  darkPink: '#FF16D1',
  lightOrange: '#FF9E7C',
  orange: '#FF7849',
  darkOrange: '#FF5216',
  lightGreen: '#29EB7F',
  green: '#13CE66',
  darkGreen: '#0F9F4F',
  lightYellow: '#FFD55F',
  yellow: '#FFC82C',
  darkYellow: '#F8B700',
  ...
};

* This palette is from Marvel's Styleguide, which you can find here.

Updating our Button

// lib/elements/Button.js

import styled from 'styled-components';
import { darken } from 'polished';
import * as colors from '../styles/colors';
const Button = styled.button`
  background: ${({ bgColor })  => colors[bgColor]};
  ...
  color: ${({ fontColor })  => colors[fontColor]};
  ...
  &:hover {
    background: ${({ bgColor })  => darken(0.1, colors[bgColor])};
  }
`;
Button.defaultProps = {
  bgColor: 'blue',
  fontColor: 'white',
};

Ok... now publish!?!

Well, hold on for a second...

Setting Button Sizes

// lib/elements/Button.js
...
const buttonSizes = {
  small: {'font-size': '14px', 'line-height': '30px', padding: '0 8px'},
  medium: {'font-size': '16px', 'line-height': '40px', padding: '0 12px'},
  large: {'font-size': '18px', 'line-height': '50px', padding: '0 16px'},
  wide: {'font-size': '16px', 'line-height': '40px', padding: '0 36px'},
  extraWide: {'font-size': '16px', 'line-height': '40px', padding: '0 72px'},
  fullWidth: {'font-size': '16px', 'line-height': '40px', padding: '0 8px'},
};

function setDisplay({ size }) {
  return size === 'fullWidth' ? 'block' : 'inline-block';
}
function setWidth({ size }) {
  return size === 'fullWidth' ? '100%' : 'initial';
}
const Button = styled.button`
  ...
  display: ${setDisplay};
  font-size: ${({ size }) => buttonSizes[size]['font-size']};
  line-height: ${({ size }) => buttonSizes[size]['line-height']};
  ...
  padding: ${({ size }) => buttonSizes[size]['padding']};
  ...
  width: ${setWidth};
  ...
`;
Button.defaultProps = {
  bgColor: 'blue',
  fontColor: 'white',
  size: 'medium',
};
...

Helpful Hints

Adopt a grid system
• Think a lot about consistent size and space

• Keep base styles simple

• Adapt styles through prop modifiers

Publishing

// from the root of your component library
$ npm login
// enter your credentials
$ npm publish
// NOTE: your email address is public
$ npm set init.author.name "Your Name"
$ npm set init.author.email "you@example.com"
$ npm set init.author.url "http://yourblog.com"
$ npm adduser
$ npm publish

Already have an account with npm? Run:

New to npm? Run:

Thanks!

Twitter @_alanbsmith

GitHub @alanbsmith

(Yes, we're hiring 🎉)

Building a Component Library

By Alan Smith

Building a Component Library

  • 704