Emma Wedekind
UX Engineer @ LogMeIn
@emmawedekind
class Emma extends Component {
state = {
name: 'Emma Wedekind',
location:'Karlsruhe, Germany',
job:'UX Engineer @ LogMeIn',
hobbies: [
'Coding Coach Founder',
'JS Party Panelist',
'Egghead.io Instructor'
]
}
}
But this is a talk about React... why do we care about architecture?
🤔
Users should not have to wonder whether different words, situations, or actions mean the same thing.
Jakob Nielsen's Heuristics
DESIGN SYSTEMS
Give designers & engineers the ability to build consistent user interfaces without wasting a ton of time and energy.
🙄
DESIGN LANGUAGE
A set of standards which guide the creation of a suite of products underneath a brand.
COMPONENT LIBRARY
A repository of standalone, coded components which turn the design language into the building blocks of an application.
STYLE GUIDE
The documentation for the design language and the component library.
WHAT MAKES A COMPONENT LIBRARY GREAT?
Accessibile
Easy to install & use
Uses modern, but adopted technologies
Responsiveness
Customization
Flexibility
DETERMINE
DESIGN
DOCUMENT
DEVELOP
DEPLOY
5-D PRIORITIZATION METHOD
Take an inventory of all components, in all products, in all states.
You must meet developers where they're at.
Don't start by building for scale.
TYPE
SIZE
ICON
THEME
LABEL
CLICK HANDLER
export const ButtonTypes = Object.freeze({
PRIMARY: "primary",
SECONDARY: "secondary",
TERTIARY: "tertiary"
});
export const ButtonSizes = Object.freeze({
SMALL: "small",
MEDIUM: "medium",
LARGE: "large"
});
export const ButtonThemes = Object.freeze({
LIGHT: "light",
DARK: "dark"
});
buttonTypes.js
// Button.jsx
import React, { Component } from 'react';
import PropTypes from 'prop-types';
import { ButtonTypes, ButtonSizes, ButtonThemes } from './buttonTypes';
import './button.css'
export default class Button extends Component {
...
render() {
const { disabled, onClickHandler, label } = this.props;
return (
<button
className={this.getButtonClasses()}
onClick={event => onClickHandler(event)}
disabled={disabled}
>
{label}
</button>
);
}
}
// Button.jsx
import React, { Component } from 'react';
import PropTypes from 'prop-types';
import { ButtonTypes, ButtonSizes, ButtonThemes } from './buttonTypes';
import './button.css'
export default class Button extends Component {
getButtonClasses() {
const { icon, size, theme, type } = this.props;
const buttonClasses = [
'button',
`button--${size}`,
`button--${theme}`,
`button--${type}`
];
return buttonClasses.join(' ');
}
render() {
...
);
}
}
// Icons.jsx
import React, { Component } from "react";
import PropTypes from "prop-types";
import { IconTypes } from "./iconTypes";
const SaveIcon = () => {
return (
<svg
xmlns="http://www.w3.org/2000/svg"
width="24"
height="24"
viewBox="0 0 24 24"
className='button__icon'
>
<title>Save</title>
...
</svg>
);
};
export default class Icon extends Component {
render() {
...
}
}
// Icons.jsx
import React, { Component } from "react";
import PropTypes from "prop-types";
import { IconTypes } from "./iconTypes";
const SaveIcon = () => {
...
};
export default class Icon extends Component {
render() {
const { icon } = this.props;
switch (icon) {
case IconTypes.SAVE:
return <SaveIcon />;
default:
return null;
}
}
}
Icon.propTypes = {
icon: PropTypes.oneOf(Object.values(IconTypes))
};
Icon.defaultProps = {
icon: IconTypes.NONE
};
// Button.jsx
...
import { IconTypes } from "./iconTypes";
import Icon from "./Icons";
export default class Button extends Component {
getButtonClasses() {
const { icon, size, theme, type } = this.props;
const buttonClasses = [
"button",
`button--${size}`,
`button--${theme}`,
`button--${type}`
];
icon && icon !== IconTypes.NONE && buttonClasses.push("button--icon");
return buttonClasses.join(" ");
}
...
}
// Button.jsx
...
export default class Button extends Component {
getButtonClasses() {
const { icon, size, theme, type } = this.props;
...
}
render() {
const { disabled, onClickHandler, label, icon } = this.props;
return (
<button
className={this.getButtonClasses()}
onClick={event => onClickHandler(event.target)}
disabled={disabled}
>
{icon && <Icon icon={icon} />}
{label}
</button>
);
}
}
// Button.jsx
...
Button.propTypes = {
type: PropTypes.oneOf(Object.values(ButtonTypes)),
disabled: PropTypes.bool,
onClickHandler: PropTypes.func.isRequired,
label: PropTypes.string.isRequired,
size: PropTypes.oneOf(Object.values(ButtonSizes)),
theme: PropTypes.oneOf(Object.values(ButtonThemes)),
icon: PropTypes.oneOf(Object.values(IconTypes))
};
Button.defaultProps = {
type: ButtonTypes.PRIMARY,
onClickHandler: () => console.log("No click handler specified"),
label: "",
disabled: false,
size: ButtonSizes.MEDIUM,
theme: ButtonThemes.LIGHT,
icon: IconTypes.NONE
};
<Button
size={ButtonSizes.MEDIUM}
label="Button"
onClickHandler={() => alert("you clicked!")}
type={ButtonTypes.PRIMARY}
/>
<Button
size={ButtonSizes.SMALL}
label="Button"
onClickHandler={() => alert("you clicked!")}
type={ButtonTypes.PRIMARY}
/>
<Button
size={ButtonSizes.LARGE}
label="Button"
theme={ButtonThemes.DARK}
onClickHandler={() => alert("you clicked!")}
type={ButtonTypes.PRIMARY}
/>
Installation & setup instructions
Installation & setup instructions
Property schema
Installation & setup instructions
Property schema
Type definition
Installation & setup instructions
Property schema
Type definition
Technology choices & rationale
Installation & setup instructions
Property schema
Type definition
Technology choices & rationale
Examples with code snippets
NATHAN CURTIS
"A design system isn't a project; it's a product serving products."
NATHAN CURTIS
"The system's promise isn't a delivered library...
its promise is to enable consistent experience spread across products."
Design systems allow us to create consistent and accessible interfaces, cross-product.
@emmawedekind
Grab my code =>
By Emma Wedekind