KEMBAR78
Building the Media Block in ReactJS | PDF
BUILDING THE MEDIA
BLOCK IN REACTJS
the API is an interface that needs to be designed
https://www.flickr.com/photos/darpi/212323100/in/photolist-jLdg7-4zEiwa-nwFCR-cZVtBE-4NHtnv-7daytd-pce3y-4NH3fh-5TLS72-58aMX7-58aMVN-a3826y-gVDVKr-8DRhUB-nEdkNf-6tnApQ-
fqJRqv-4NMHx7-7fUPoM-cNu2W-8etirE-o7PZA-wsB4L-7ABatu-8LyEF5-7iEjwY-3faCd1-9Gn1fF-4qYRms-JUKbE-7B97bb-69Uer5-5DQMzG-f4ZgsG-7TvUJp-5zyhEh-65naZh-nBkNs-5eCcAF-sErjv-4ePHGY-6kV1Q4-
nxWYX-dpGR5-55vgqd-5scyot-5t7uJJ-nLQn5y-9Njbu-79B4aw
@STUBBORNELLA
twitter really is the best way to reach me…
WHAT WILL WE COVER?
❖ What is a media block?	

❖ Why use ReactJS	

❖ Making a media block in ReactJS
WHAT IS THE MEDIA
BLOCK?
let’s look at an example from Facebook
MEDIA BLOCK EXAMPLE
ALL OF THESE ARE THE
SAME OBJECT
WHAT DO WE KNOW?
!
❖ Can be nested	

❖ Optional right button	

❖ Must clearfix
WHAT DO WE KNOW?
!
❖ Allows top, middle, or
bottom alignment
WHAT DON’T WE KNOW?
❖ Image width and decoration vary	

❖ Right content is unknown	

❖ Width unknown
A FEW LINES OF HTML...
<div class="media attribution">	
<a href="http://twitter.com/stubbornella" class="img">	
<img src="mini.jpg" alt="Stubbornella" />	
</a>	
<div class="bd">@Stubbornella 14 minutes ago</div>	
</div>
4 LINES OF CSS...
_
I <3 HTML, WHY USE
REACT?
❖ html consistency (modal debugging)	

❖ smaller api (fewer breaking changes)	

❖ don’t need to go everywhere a component
was used to update the dom if it changes	

❖ lightning fast dom updates when data
changes	

❖ not managing those updates manually	

❖ simpler APIs (tabs example)
I CAN’T
COVER
EVERYTHING
So do Ryan Florence’s
tutorials: 	

https://github.com/
ryanflorence/react-training/
https://www.flickr.com/photos/wscullin/3770015991/in/photolist-6K9jpH-4mbNmG-4Cryx-6K9jC4-9hYhWK-dexZ3L-bpV8UA-6K9jb8-2aRBU9-c2mfZu-8desRa-ntKGaS-8ZxBba-7RVQRi-7AbLTM-dMTqW3-4866mH-rjNaZL-7MP9RU-
dhfQ5N-rfCB9g-nBshnQ-7Xn7f-87asnj-84R7FU-sepy36-dtEmrp-rhsh7A-hVCY8u-4m7NmB-qqiNK6-bMLUPp-qY4LbS-q1prK-5WoP4f-Ftxe-4mbHVY-jB4t16-5qgm94-5WjwED-7vS6fV-5WoP4N-biVihz-9KsFUo-9KpQVF-9KpQMz-
BUILDING THE MEDIA
BLOCK IN REACT
APIs are an interface that needs to be designed
WHAT ARE THE ELEMENTS
OF A REACT INTERFACE
❖ Elements	

❖ Attributes 	

❖ Nested children	

❖ Data
Sounds a lot like html, right?
HOW DO YOU MAKE A
MEDIA COMPONENT?
in React
Code
var Media = React.createClass({
!
});
SO THEN, HOW WOULD
YOU USE IT?
It’s kind of like HTML, it’s called jsx
<Media>
My very first React component!
</Media>
BUT, WE NEED TO EXPORT
the Media component, so it can be used in other files
module.exports = {
Media: Media
};
DESCRIBE IT WITH A
RENDER FUNCTION
This tells the browser what HTML to render.
var Media = React.createClass({
render: function () {
return (
<p>
{this.props.children}
</p>
);
}
});
just render a paragraph, for now
tell React where to
render children
WHAT
!
!
!
IS GENERATED?
https://www.flickr.com/photos/f-l-e-x/3096005116/in/photolist-5HzQsy-ah1UJ3-9WjzQW-q6xrU5-eQkJhu-oWah5L-noSbAV-9nNZaQ-5XZ3To-9gi7Rx-eMzU1y-9gb3m8-eQ8LqD-9WSkjF-9WSkhK-9zurtr-9WSk3X-eQkasL-eQ8GQ6-
gi65Qe-9gbgVc-9geLWE-9gbiwR-k3TpbP-9EiwTi-bMTAYe-aYNGWB-6VTDDM-96t4ms-9s4Jas-bsjtmK-edG4Dq-rFb2Q-aZYKCH-Paes6-sd9Vtx-eg9fuW-9rYCnp-edgbX5-bmrzPv-9qA9iA-aMgUmz-s1AMwV-9zurqp-gXd9UH-
iEyyC-3NaTMa-bodPpW-dLeWjL-bxHrbz
LET’S TRY IT!
Sweet, this is gonna be rad.
<Media>
This text is our component’s children!
</Media>
!
!
!
!
<p>
This text is our component’s children!
</p>
LET’S TRY IT!
Sweet, this is gonna be rad.
<Media>
This text is our component’s children!
</Media>
!
!
!
!
<p>
This text is our component’s children!
</p>
When React renders that
component we get this html
LET’S TRY IT!
Sweet, this is gonna be rad.
<Media>
This text is our component’s children!
</Media>
!
!
!
!
<p>
This text is our component’s children!
</p>
{this.props.children}
When React renders that
component we get this html
NOT VERY USEFUL, RIGHT?
You'd never use react to render a simple paragraph because it
already understands <p> tags, you can just use them!
LET’S BUILD AN ACTUAL
MEDIA BLOCK
Step 1:Add the left image
SO, WHAT DID WE TRY
FIRST?
https://www.flickr.com/photos/mstewartphotography/6195718653/in/photolist-aruFip-3Ym2sP-d5ipmU-61ivfM-2SmfSo-eMWyyv-7Tx3yN-p7xVZN-5LExX5-dG1RK2-86LsMW-6TDV5Y-9isMj1-cJuUm-4v2NE-
amKvge-61TfaY-61PcSp-61nGEd-86FasK-qrz8VS-4bGoKp-77DPsN-7NeZKn-botCkn-8vpoEE-oTAKWV-5Sz1Fv-a5oF29-86Hf14-aS9vmZ-a8M5q6-a8Mh8k-7AKzoA-86HcPz-61HM17-7AFRcK-a8LXht-5c5LvE-a8LZXX-61Hb8A-
fJgHuw-86LhDq-86Lmch-3jzdZ-5mYENE-8UMWoM-bx1iUr-p9jsSa-a865Ji
https://www.flickr.com/photos/mstewartphotography/6195718653/in/photolist-aruFip-3Ym2sP-d5ipmU-61ivfM-2SmfSo-eMWyyv-7Tx3yN-p7xVZN-5LExX5-dG1RK2-86LsMW-6TDV5Y-9isMj1-cJuUm-4v2NE-
amKvge-61TfaY-61PcSp-61nGEd-86FasK-qrz8VS-4bGoKp-77DPsN-7NeZKn-botCkn-8vpoEE-oTAKWV-5Sz1Fv-a5oF29-86Hf14-aS9vmZ-a8M5q6-a8Mh8k-7AKzoA-86HcPz-61HM17-7AFRcK-a8LXht-5c5LvE-a8LZXX-61Hb8A-
fJgHuw-86LhDq-86Lmch-3jzdZ-5mYENE-8UMWoM-bx1iUr-p9jsSa-a865Ji
TONS OF ATTRIBUTES
What could go wrong? ;)
https://www.flickr.com/photos/ilo_oli/5856288807/in/photolist-jpnSsc-bp1mTF-iC3JNn-feu2hV-feJdEw-dCsd6V-aQmwUk-qJvwYx-qKHp7N-qKJtpL-pMFnAC-9XxWkr-qKJEV1-q6hte9-qZZXHG-q6hp8d-qKHchA-qKJt8U-bp1mv2-
b6LSWT-bKfSon-kxWCNt-b6LNN8-b8Vpk6-ehScwd-c5CMgq-qKJcqw-r3iaXK-pMieGe-9ZUFNi-aD4zaE-fDwLBF-9Vv1CF-kzarYi-9ovVLy-rVLApS-fDwKki-b5sxAg-fskG7P-bUUme1-bKgdD6-c5CMiW-a1wsSP-4u7U5a-dtv95k-dtvKP6-
dtBtwJ-dtvrRR-dtBm2s-abcAqR
CREATE A SOURCE
ATTRIBUTE
We’ll use it in our render function to set the src of the image
<Media leftImageSource='http://placehold.it/50x50'>
Media block content
</Media>
React props are a
lot like HTML
attributes
BUT WAIT, THE IMAGE CAN
BE A LINK
Sometimes…
SO, LET’S ADD AN HREF
ATTRIBUTE
<Media
leftImageSource='http://placehold.it/50x50'
leftImageHref='http://www.google.com'>
Media block content
</Media>
Our render function will
make this into a link
wrapper (if it is set)
THE IMAGE CAN BE
VERTICALLY ALIGNED
ADD AN ALIGNMENT
ATTRIBUTE
<Media
leftImageSource='http://placehold.it/50x50'
leftImageHref='http://www.google.com'
leftImageAlignment='middle'>
Media block content
</Media>
vertical alignment, could be
top, middle or bottom
OH SHOOT, ACCESSIBILITY!
WE NEED AN ALT
ATTRIBUTE
<Media
leftImageSource='http://placehold.it/50x50'
leftImageHref='http://www.google.com'
leftImageAlignment='middle'
leftImageAlt="profile photo">
Media block content
</Media>
Our render function will make
this into an alt attribute on the
<img> tag
OH, AND PERFORMANCE!
WE NEED A HEIGHT AND
WIDTH
<Media
leftImageSource='http://placehold.it/50x50'
leftImageHref='http://www.google.com'
leftImageAlignment='middle'
leftImageAlt="profile photo"
leftImageHeight="50px"
leftImageWidth="50px">
Media block content
</Media>
Explicit height and width
allow the browser to do a
single rendering/painting
pass
SET THE GUTTER BETWEEN
IMAGE AND CONTENT
with the spacing attribute
<Media
leftImageSource='http://placehold.it/50x50'
leftImageHref='http://www.google.com'
leftImageAlignment='middle'
leftImageAlt="profile photo"
leftImageHeight="50px"
leftImageWidth="50px"
leftImageSpacing="medium">
Media block content
</Media>
For when the 10px default
spacing isn’t right, like a tiny
icon with text
PROPERTIES OF THE MEDIA
rather than its images
FOR EXAMPLE, IT’S
RESPONSIVE
via the stacksize (breakpoint) attribute
<Media
leftImageSource='http://placehold.it/50x50'
leftImageHref='http://www.google.com'
leftImageAlignment='middle'
leftImageAlt="profile photo"
leftImageHeight="50px"
leftImageWidth="50px"
leftImageSpacing="medium"
stackSize='medium'>
Media block content
</Media>
stack size puts the image
above the text at the
breakpoint
THIS IS GETTING
OUT OF HAND!
But we forgot something, the media block can have a right
image
ADD THE RIGHT IMAGE
PROPERTIES
This is out of control, we are going the wrong way!
<Media
leftImageSource='http://placehold.it/50x50'
leftImageHref='http://www.google.com'
leftImageAlignment='middle'
leftImageAlt="profile photo"
leftImageHeight="50px"
leftImageWidth="50px"
rightImageSource='http://placehold.it/50x50'
rightImageHref='http://www.google.com'
rightImageAlignment='middle'
rightImageAlt="profile photo"
rightImageHeight="50px"
rightImageWidth="50px"
rightImageSpacing="medium"
bodyAlignment='middle'
stackSize='medium'>
Media block content
</Media>
right image
props
PROS/CONS
❖ It’s very explicit, we know
what each thing does
What works?
❖ We're basically recreating
html in React, yuck! (we
shouldn’t make a new
different alt attribute!	

❖ We have image properties
and media properties all
mixed up	

❖ We have too many
properties
What doesn’t work?
SO, WHAT DID WE TRY
NEXT?
https://www.flickr.com/photos/mstewartphotography/6195718653/in/photolist-aruFip-3Ym2sP-d5ipmU-61ivfM-2SmfSo-eMWyyv-7Tx3yN-p7xVZN-5LExX5-dG1RK2-86LsMW-6TDV5Y-9isMj1-cJuUm-4v2NE-
amKvge-61TfaY-61PcSp-61nGEd-86FasK-qrz8VS-4bGoKp-77DPsN-7NeZKn-botCkn-8vpoEE-oTAKWV-5Sz1Fv-a5oF29-86Hf14-aS9vmZ-a8M5q6-a8Mh8k-7AKzoA-86HcPz-61HM17-7AFRcK-a8LXht-5c5LvE-a8LZXX-61Hb8A-
fJgHuw-86LhDq-86Lmch-3jzdZ-5mYENE-8UMWoM-bx1iUr-p9jsSa-a865Ji
https://www.flickr.com/photos/mstewartphotography/6195718653/in/photolist-aruFip-3Ym2sP-d5ipmU-61ivfM-2SmfSo-eMWyyv-7Tx3yN-p7xVZN-5LExX5-dG1RK2-86LsMW-6TDV5Y-9isMj1-cJuUm-4v2NE-
amKvge-61TfaY-61PcSp-61nGEd-86FasK-qrz8VS-4bGoKp-77DPsN-7NeZKn-botCkn-8vpoEE-oTAKWV-5Sz1Fv-a5oF29-86Hf14-aS9vmZ-a8M5q6-a8Mh8k-7AKzoA-86HcPz-61HM17-7AFRcK-a8LXht-5c5LvE-a8LZXX-61Hb8A-
fJgHuw-86LhDq-86Lmch-3jzdZ-5mYENE-8UMWoM-bx1iUr-p9jsSa-a865Ji
JSON ALL THE THINGS
https://www.flickr.com/photos/bike/4797449644/in/photolist-8iWbD3-5HPWhF-QyKg5-eVYyjt-3meRNg-5HPW94-4HwYMz-utah8-3qvXS-aqsJtx-eyQK4T-42P9p1-7Th995-5oKgDS-5mJEJe-9bt9At-4zbwwo-8vDr8Z-7konhy-
BhrJ9-5zHQ7E-bobveq-DmrMg-3qvNs-5HPW1P-qtLJmp-5ZCPcW-9QuNBj-5HUdgS-9thCcq-6FmTKV-7QgAua-6DZyzu-gkukag-apwsgp-8hWccC-4U7EX6-pfaKPb-hvM3q-asXuSH-at18RL-asXuDV-asXuC4-9ys6M7-phFVSp-
dkdPkb-86toqn-dzVg-zVaLA-cDsK7N
OUR IMAGES AS JSON
kinda weird, but it might work…
var images = [
{
"src": "http://placehold.it/50x50",
"href": "http://www.google.com",
"alignment": "middle",
"alt": "profile photo",
"height": "50px",
"width": "50px"
},
{
"src": "http://placehold.it/50x50",
"href": "http://www.google.com",
"alignment": "middle",
"alt": "profile photo",
"height": "50px",
"width": "50px"
}
];
JSON IN THE MEDIA
passed in as another property
<Media
images={images}
bodyAlignment='middle'
stackSize='medium'>
Media block content
</Media>
JSON IN THE MEDIA
passed in as another property
<Media
images={images}
bodyAlignment='middle'
stackSize='medium'>
Media block content
</Media>
{curly braces} mean it’s a JavaScript
variable rather than a string
JSON IN THE MEDIA
passed in as another property
<Media
images={images}
bodyAlignment='middle'
stackSize='medium'>
Media block content
</Media>
json goes into the
images attribute
{curly braces} mean it’s a JavaScript
variable rather than a string
What works? What doesn’t work?
PROS/CONS
❖ abstraction of passing in
JSON means all the code
isn't in the same place	

❖ weird to have JSON in the
middle of what looks like
markup	

❖ still reinventing html
attributes of an <img> tag
❖ cleaner separation of
concerns (media takes care
of media stuff, rather than
the properties of its
children)
WHAT DID WE DO NEXT?
https://www.flickr.com/photos/mstewartphotography/6195718653/in/photolist-aruFip-3Ym2sP-d5ipmU-61ivfM-2SmfSo-eMWyyv-7Tx3yN-p7xVZN-5LExX5-dG1RK2-86LsMW-6TDV5Y-9isMj1-cJuUm-4v2NE-
amKvge-61TfaY-61PcSp-61nGEd-86FasK-qrz8VS-4bGoKp-77DPsN-7NeZKn-botCkn-8vpoEE-oTAKWV-5Sz1Fv-a5oF29-86Hf14-aS9vmZ-a8M5q6-a8Mh8k-7AKzoA-86HcPz-61HM17-7AFRcK-a8LXht-5c5LvE-a8LZXX-61Hb8A-
fJgHuw-86LhDq-86Lmch-3jzdZ-5mYENE-8UMWoM-bx1iUr-p9jsSa-a865Ji
https://www.flickr.com/photos/mstewartphotography/6195718653/in/photolist-aruFip-3Ym2sP-d5ipmU-61ivfM-2SmfSo-eMWyyv-7Tx3yN-p7xVZN-5LExX5-dG1RK2-86LsMW-6TDV5Y-9isMj1-cJuUm-4v2NE-
amKvge-61TfaY-61PcSp-61nGEd-86FasK-qrz8VS-4bGoKp-77DPsN-7NeZKn-botCkn-8vpoEE-oTAKWV-5Sz1Fv-a5oF29-86Hf14-aS9vmZ-a8M5q6-a8Mh8k-7AKzoA-86HcPz-61HM17-7AFRcK-a8LXht-5c5LvE-a8LZXX-61Hb8A-
fJgHuw-86LhDq-86Lmch-3jzdZ-5mYENE-8UMWoM-bx1iUr-p9jsSa-a865Ji
PARSING CHILDREN
We decided to try including the images as children
https://www.flickr.com/photos/i-am-mclovin/16535518502/in/photolist-rcbRyA-nshV4n-eAaqTz-bCfUFZ-jH4tBF-pctQQD-qNmfZS-eT3GMZ-bTJsji-N8LkW-iCxgoA-7JDTp2-mPGu7V-dV4m7G-igpkaV-dRobZv-mnUN9i-igoYgJ-bCzBBi-
f9tdxa-oMiWTE-b6LMzz-rcTY6S-dYq12b-qUh6hV-f6oFCx-pmwC9Z-hNLucH-moYnBt-6uGwja-aRrBm4-mPGGDB-igp6YC-f8b3QR-igpkXB-igoY3C-o62zzh-iC3JNn-9217QQ-D3JPG-pcHyUy-pprMfU-igoJAg-hgRxSL-pqomg9-
ahQDpD-4LkbKg-hNLcDy-igoJb8-9STs34
PARSING CHILDREN
better, everything is normal html! But, it has a few drawbacks
<Media>
<img src='http://placehold.it/50x50'
href='http://www.google.com' alignment='middle'
alt="profile photo" height="50px" width="50px" >
<p>My media content</p>
<img src='http://placehold.it/50x50'
href='http://www.google.com' alignment='middle'
alt="profile photo" height="50px" width="50px" >
</Media>
What works? What doesn’t work?
PROS/CONS
❖ The images and body
content need to be in a very
particular order, it seems
weird to expose that to the
user	

❖ Violates the "build
components you can use
without understanding CSS”
principle
❖ Normal HTML	

❖ Facebook does it this way
WHAT *ELSE* DOESN’T
WORK?
❖ We could loop over children and reorder them, but how do
we tell the difference between content images and media
images?	

❖ We were still discovering React, and didn't know how to loop
over children yet	

❖ React provides handy error messages and property validations.
We would lose out on that if we made the images children	

❖ Facebook's images aren't optional, so it's a different case
SO, WHAT DID WE TRY
NEXT?
https://www.flickr.com/photos/mstewartphotography/6195718653/in/photolist-aruFip-3Ym2sP-d5ipmU-61ivfM-2SmfSo-eMWyyv-7Tx3yN-p7xVZN-5LExX5-dG1RK2-86LsMW-6TDV5Y-9isMj1-cJuUm-4v2NE-
amKvge-61TfaY-61PcSp-61nGEd-86FasK-qrz8VS-4bGoKp-77DPsN-7NeZKn-botCkn-8vpoEE-oTAKWV-5Sz1Fv-a5oF29-86Hf14-aS9vmZ-a8M5q6-a8Mh8k-7AKzoA-86HcPz-61HM17-7AFRcK-a8LXht-5c5LvE-a8LZXX-61Hb8A-
fJgHuw-86LhDq-86Lmch-3jzdZ-5mYENE-8UMWoM-bx1iUr-p9jsSa-a865Ji
https://www.flickr.com/photos/mstewartphotography/6195718653/in/photolist-aruFip-3Ym2sP-d5ipmU-61ivfM-2SmfSo-eMWyyv-7Tx3yN-p7xVZN-5LExX5-dG1RK2-86LsMW-6TDV5Y-9isMj1-cJuUm-4v2NE-
amKvge-61TfaY-61PcSp-61nGEd-86FasK-qrz8VS-4bGoKp-77DPsN-7NeZKn-botCkn-8vpoEE-oTAKWV-5Sz1Fv-a5oF29-86Hf14-aS9vmZ-a8M5q6-a8Mh8k-7AKzoA-86HcPz-61HM17-7AFRcK-a8LXht-5c5LvE-a8LZXX-61Hb8A-
fJgHuw-86LhDq-86Lmch-3jzdZ-5mYENE-8UMWoM-bx1iUr-p9jsSa-a865Ji
REACT BUILT-IN <IMG>
COMPONENT
In react, everything is a component.
FIRST, WE MAKE OUR
IMAGES
var leftImage = <img src='http://placehold.it/
50x50' href='http://www.google.com'
alignment='middle' alt="profile photo"
height="50px" width="50px">;
!
var rightImage = <img src='http://placehold.it/
50x50' href='http://www.google.com'
alignment='middle' alt="profile photo"
height="50px" width=“50px">;
NEXT, WE MAKE OUR
MEDIA OBJECT
this looks similar to the JSON example
<Media
leftImage={leftImage}
rightImage={rightImage}
bodyAlignment='middle'
stackSize='medium'>
Media block content
</Media>
NEXT, WE MAKE OUR
MEDIA OBJECT
this looks similar to the JSON example
<Media
leftImage={leftImage}
rightImage={rightImage}
bodyAlignment='middle'
stackSize='medium'>
Media block content
</Media>
left and right images are
passed into attributes
YOU CAN EVEN WRITE IT
like this if you really want to
<Media
leftImage={<img src='http://placehold.it/50x50'
href='http://www.google.com' alignment='middle'
alt="profile photo" height="50px" width="50px">}
bodyAlignment='middle'
stackSize='medium'>
Media block content
</Media>
image component directly in
the attribute property
What works? What doesn’t work?
PROS/CONS
❖ HTML inside an attribute (in
the latter example) is a bit
odd, though it does have
advantages.
❖ React passes default html
attributes in to the resulting
img tag, so we don't have to
do anything special with
height, width, src, aria and alt.	

❖ We separate concerns and
the image takes care of it's
own properties	

❖ No need to parse content
WHAT *ELSE* DOESN’T
WORK?
❖ href will be passed through. So our image will have an href
attribute. I like clean html, and that feels weird to me!
<div class="media">
<a href="styleguide.pivotal.io">
<img href="styleguide.pivotal.io" />
...
Yuck!
WE CONSIDERED GOING
BACK TO PROPERTIES…
but decided we should make our own <img> wrapper
<Media leftImageHref="styleguide.pivotal.io">
to property or not to property?
SO, WHAT DID WE TRY
NEXT?
https://www.flickr.com/photos/mstewartphotography/6195718653/in/photolist-aruFip-3Ym2sP-d5ipmU-61ivfM-2SmfSo-eMWyyv-7Tx3yN-p7xVZN-5LExX5-dG1RK2-86LsMW-6TDV5Y-9isMj1-cJuUm-4v2NE-
amKvge-61TfaY-61PcSp-61nGEd-86FasK-qrz8VS-4bGoKp-77DPsN-7NeZKn-botCkn-8vpoEE-oTAKWV-5Sz1Fv-a5oF29-86Hf14-aS9vmZ-a8M5q6-a8Mh8k-7AKzoA-86HcPz-61HM17-7AFRcK-a8LXht-5c5LvE-a8LZXX-61Hb8A-
fJgHuw-86LhDq-86Lmch-3jzdZ-5mYENE-8UMWoM-bx1iUr-p9jsSa-a865Ji
https://www.flickr.com/photos/mstewartphotography/6195718653/in/photolist-aruFip-3Ym2sP-d5ipmU-61ivfM-2SmfSo-eMWyyv-7Tx3yN-p7xVZN-5LExX5-dG1RK2-86LsMW-6TDV5Y-9isMj1-cJuUm-4v2NE-
amKvge-61TfaY-61PcSp-61nGEd-86FasK-qrz8VS-4bGoKp-77DPsN-7NeZKn-botCkn-8vpoEE-oTAKWV-5Sz1Fv-a5oF29-86Hf14-aS9vmZ-a8M5q6-a8Mh8k-7AKzoA-86HcPz-61HM17-7AFRcK-a8LXht-5c5LvE-a8LZXX-61Hb8A-
fJgHuw-86LhDq-86Lmch-3jzdZ-5mYENE-8UMWoM-bx1iUr-p9jsSa-a865Ji
CUSTOM IMAGE
COMPONENT
And another component was born…
https://www.flickr.com/photos/eltonharding/522073772/in/photolist-N8LkW-dLnt39-dsdYRQ-qcf3KQ-rgojpc-dsdWxA-dRxje9-iAgtmB-aaTYBU-mgGFrk-d3TMAf-opZhPw-nbi6ut-gMDt1W-adGAGZ-j8HqHK-gAt6ec-mc944B-
nEMWpG-oQkVQ4-qR9xvi-gSVfC5-oUurRb-9jGTJD-nWUZza-e5NeHJ-aTYLCT-dTTRha-rp3zLC-qn7i8t-hQxDrG-9qcih5-sn5TTi-9aQfXm-nsgfeC-niFxPL-dRxjy7-9Ry7C3-p8VRa4-noA5cx-oovJdV-kLSLxL-dpgFWM-rhZ9Ri-
dRxkm3-9qResk-kGDeJb-bprRNw-oCC5tt-oCX7iY
GOAL: OUTPUTS A SIMPLE
<IMG> TAG
but won't pass through attributes 	

that don't make sense like href
STEP 1: CREATE THE IMAGE
COMPONENT
var Image = React.createClass({
!
});
STEP 2: EXPORT THE IMAGE
the same way we did the Media component
module.exports = {Image};
STEP 3: GET ITS PROPERTIES
and render an image
var Image = React.createClass({
render() {
var {href, src, children, className, ...other} = this.props;
!
var image = <img {...other} src={src} className={classes}>;
!
return href ? <a {...{href}}>{image}</a> : image;
}
});
STEP 3: GET ITS PROPERTIES
and render an image
var Image = React.createClass({
render() {
var {href, src, children, className, ...other} = this.props;
!
var image = <img {...other} src={src} className={classes}>;
!
return href ? <a {...{href}}>{image}</a> : image;
}
});
get the properties we need
STEP 3: GET ITS PROPERTIES
and render an image
var Image = React.createClass({
render() {
var {href, src, children, className, ...other} = this.props;
!
var image = <img {...other} src={src} className={classes}>;
!
return href ? <a {...{href}}>{image}</a> : image;
}
});
get the properties we need
build the image from our properties
STEP 3: GET ITS PROPERTIES
and render an image
var Image = React.createClass({
render() {
var {href, src, children, className, ...other} = this.props;
!
var image = <img {...other} src={src} className={classes}>;
!
return href ? <a {...{href}}>{image}</a> : image;
}
});
get the properties we need
build the image from our properties
if we have a link, wrap the image in an <a> tag
STEP 4: MAKE IT
RESPONSIVE
by handling the responsive boolean
var Image = React.createClass({
render() {
var {responsive, href, src, children, className, ...other} = this.props;
!
var image = <img {...other} src={src}>;
return href ? <a {...{href}}>{image}</a> : image;
}
});
STEP 4: MAKE IT
RESPONSIVE
by handling the responsive boolean
var Image = React.createClass({
render() {
var {responsive, href, src, children, className, ...other} = this.props;
!
var image = <img {...other} src={src}>;
return href ? <a {...{href}}>{image}</a> : image;
}
});
get the responsive property
STEP 4: MAKE IT
RESPONSIVE
and setting the img-responsive class if the boolean is true
var Image = React.createClass({
render() {
var {responsive, href, src, children, className, ...other} = this.props;
!
var classes = classnames({'img-responsive': responsive}, className);
!
!
!
!
!
!
!
var image = <img {...other} src={src} className={classes}>{children}</img>;
return href ? <a {...{href}}>{image}</a> : image;
}
});
STEP 4: MAKE IT
RESPONSIVE
and setting the img-responsive class if the boolean is true
var Image = React.createClass({
render() {
var {responsive, href, src, children, className, ...other} = this.props;
!
var classes = classnames({'img-responsive': responsive}, className);
!
!
!
!
!
!
!
var image = <img {...other} src={src} className={classes}>{children}</img>;
return href ? <a {...{href}}>{image}</a> : image;
}
});
add this class
if this evaluates
to true
STEP 4: MAKE IT
RESPONSIVE
and setting the img-responsive class if the boolean is true
var Image = React.createClass({
render() {
var {responsive, href, src, children, className, ...other} = this.props;
!
var classes = classnames({'img-responsive': responsive}, className);
!
!
!
!
!
!
!
var image = <img {...other} src={src} className={classes}>{children}</img>;
return href ? <a {...{href}}>{image}</a> : image;
}
});
add this class
if this evaluates
to true
then, put the class
on the image
STEP 5: VALIDATE
PROPERTIES
var Image = React.createClass({
propTypes: {
responsive: types.bool,
href: types.string,
src: types.string.isRequired
},
!
render() {
var {responsive, href, src, children, className, ...other} = this.props;
var classes = classnames({'img-responsive': responsive}, className);
!
var image = <img {...other} src={src} className={classes}>{children}</img>;
return href ? <a {...{href}}>{image}</a> : image;
}
});
STEP 5: VALIDATE
PROPERTIES
var Image = React.createClass({
propTypes: {
responsive: types.bool,
href: types.string,
src: types.string.isRequired
},
!
render() {
var {responsive, href, src, children, className, ...other} = this.props;
var classes = classnames({'img-responsive': responsive}, className);
!
var image = <img {...other} src={src} className={classes}>{children}</img>;
return href ? <a {...{href}}>{image}</a> : image;
}
});
responsive has to
be true or false
STEP 5: VALIDATE
PROPERTIES
var Image = React.createClass({
propTypes: {
responsive: types.bool,
href: types.string,
src: types.string.isRequired
},
!
render() {
var {responsive, href, src, children, className, ...other} = this.props;
var classes = classnames({'img-responsive': responsive}, className);
!
var image = <img {...other} src={src} className={classes}>{children}</img>;
return href ? <a {...{href}}>{image}</a> : image;
}
});
STEP 5: VALIDATE
PROPERTIES
var Image = React.createClass({
propTypes: {
responsive: types.bool,
href: types.string,
src: types.string.isRequired
},
!
render() {
var {responsive, href, src, children, className, ...other} = this.props;
var classes = classnames({'img-responsive': responsive}, className);
!
var image = <img {...other} src={src} className={classes}>{children}</img>;
return href ? <a {...{href}}>{image}</a> : image;
}
});
the href is a string
STEP 5: VALIDATE
PROPERTIES
var Image = React.createClass({
propTypes: {
responsive: types.bool,
href: types.string,
src: types.string.isRequired
},
!
render() {
var {responsive, href, src, children, className, ...other} = this.props;
var classes = classnames({'img-responsive': responsive}, className);
!
var image = <img {...other} src={src} className={classes}>{children}</img>;
return href ? <a {...{href}}>{image}</a> : image;
}
});
STEP 5: VALIDATE
PROPERTIES
var Image = React.createClass({
propTypes: {
responsive: types.bool,
href: types.string,
src: types.string.isRequired
},
!
render() {
var {responsive, href, src, children, className, ...other} = this.props;
var classes = classnames({'img-responsive': responsive}, className);
!
var image = <img {...other} src={src} className={classes}>{children}</img>;
return href ? <a {...{href}}>{image}</a> : image;
}
});
src is a string and
required
STEP 5: VALIDATE
PROPERTIES
var Image = React.createClass({
propTypes: {
responsive: types.bool,
href: types.string,
src: types.string.isRequired
},
!
render() {
var {responsive, href, src, children, className, ...other} = this.props;
var classes = classnames({'img-responsive': responsive}, className);
!
var image = <img {...other} src={src} className={classes}>{children}</img>;
return href ? <a {...{href}}>{image}</a> : image;
}
});
STEP 5: VALIDATE
PROPERTIES
var Image = React.createClass({
propTypes: {
responsive: types.bool,
href: types.string,
src: types.string.isRequired
},
!
render() {
var {responsive, href, src, children, className, ...other} = this.props;
var classes = classnames({'img-responsive': responsive}, className);
!
var image = <img {...other} src={src} className={classes}>{children}</img>;
return href ? <a {...{href}}>{image}</a> : image;
}
});
OUR “AH-HA” MOMENT
Users are still needing to specify too many things to get this
component to work, they might as well just write html!
SO, WHAT DID WE DO
NEXT?
https://www.flickr.com/photos/mstewartphotography/6195718653/in/photolist-aruFip-3Ym2sP-d5ipmU-61ivfM-2SmfSo-eMWyyv-7Tx3yN-p7xVZN-5LExX5-dG1RK2-86LsMW-6TDV5Y-9isMj1-cJuUm-4v2NE-
amKvge-61TfaY-61PcSp-61nGEd-86FasK-qrz8VS-4bGoKp-77DPsN-7NeZKn-botCkn-8vpoEE-oTAKWV-5Sz1Fv-a5oF29-86Hf14-aS9vmZ-a8M5q6-a8Mh8k-7AKzoA-86HcPz-61HM17-7AFRcK-a8LXht-5c5LvE-a8LZXX-61Hb8A-
fJgHuw-86LhDq-86Lmch-3jzdZ-5mYENE-8UMWoM-bx1iUr-p9jsSa-a865Ji
https://www.flickr.com/photos/mstewartphotography/6195718653/in/photolist-aruFip-3Ym2sP-d5ipmU-61ivfM-2SmfSo-eMWyyv-7Tx3yN-p7xVZN-5LExX5-dG1RK2-86LsMW-6TDV5Y-9isMj1-cJuUm-4v2NE-
amKvge-61TfaY-61PcSp-61nGEd-86FasK-qrz8VS-4bGoKp-77DPsN-7NeZKn-botCkn-8vpoEE-oTAKWV-5Sz1Fv-a5oF29-86Hf14-aS9vmZ-a8M5q6-a8Mh8k-7AKzoA-86HcPz-61HM17-7AFRcK-a8LXht-5c5LvE-a8LZXX-61Hb8A-
fJgHuw-86LhDq-86Lmch-3jzdZ-5mYENE-8UMWoM-bx1iUr-p9jsSa-a865Ji
ELEMENTS FTW
we can simplify our interface further
https://www.flickr.com/photos/rejik/14681743931/in/photolist-onnLY4-nPYfhm-ed6PWM-bvWmjA-mMGE1V-j88ToM-ngTbpk-nUg38a-9n1hgv-4KZr2Z-nucMef-dd5exw-9eyaqy-8QWK1i-eaTuFL-4RbvFX-7kiwo3-7NqP2a-4R1KYB-
mZEx1J-5iV12q-39v9f8-bqt2rx-7zvWs-9eyamJ-7JKZAh-hiwiDa-poG8fx-ehZRGj-684GeT-pPeQGL-efRP9f-icXKJY-aNxWqT-9niyKk-ouarpw-bmC5SK-7s5DNV-bqt3F8-bqsZ24-mZCLWp-86YqXk-e6ERub-bqtEL8-8K3pJf-
kik4tg-8yYivi-8fi3Ep-dVohpu-fzmggH
https://www.flickr.com/photos/rejik/14681743931/in/photolist-onnLY4-nPYfhm-ed6PWM-bvWmjA-mMGE1V-j88ToM-ngTbpk-nUg38a-9n1hgv-4KZr2Z-nucMef-dd5exw-9eyaqy-8QWK1i-eaTuFL-4RbvFX-7kiwo3-7NqP2a-4R1KYB-
mZEx1J-5iV12q-39v9f8-bqt2rx-7zvWs-9eyamJ-7JKZAh-hiwiDa-poG8fx-ehZRGj-684GeT-pPeQGL-efRP9f-icXKJY-aNxWqT-9niyKk-ouarpw-bmC5SK-7s5DNV-bqt3F8-bqsZ24-mZCLWp-86YqXk-e6ERub-bqtEL8-8K3pJf-
kik4tg-8yYivi-8fi3Ep-dVohpu-fzmggH
DESIGNERS ONLY USE 2
KINDS OF ALIGNMENT
❖ Traditional media with everything top aligned	

!
!
!
❖ “Flag” component a la Harry Roberts middle aligns
WE MADE THESE TWO USE
CASES DEAD SIMPLE
❖ We changed the media component to default to top
alignment if nothing else was specified.	

❖ We created the <flag> component
<Flag leftImage={refreshImage}>
refresh
</Flag>
What works? What doesn’t work?
PROS/CONS
❖ engineers don't always know
what the flag object is,
documentation and teaching
help
❖ with Flag and Media, we no
longer need to specify
alignment unless we want
something weird
ARE ANY OF THESE
WRONG?
No, absolutely not.
https://gist.github.com/stubbornella/e97662e4a197eb9a534a
CHARTS
loop over children
https://www.flickr.com/photos/sidereal/3326112973/in/photolist-AKC4i-9YVVYN-6EiwN6-GadYk-a67Nur-5VXHT1-Fv7K6-aozvYE-6fp6gc-6FzLjQ-fKvtt-2JGK9-bqeuyX-3jcvLj-Ljyy3-6kUXKM-
bVyHMC-4dDwYk-5CGecv-6DUvgk-64Vcvp-8cK4x4-6b5yLD-jDwYG-wnfrN-vdeo8-8343Sa-dRCSgx-83wSzz-5xtVxe-5xyrZd-5VDSw6-
fXTYR-82Dnu2-5VDSwa-7MNruk-81biBH-5e3irn-5e3i4T-6mxH7A-5m93Dg-5pi6WC-5uvUeA-6n89sp-c465FQ-6SDa5S-5AbJnS-cN17Zf-KGVTi-7yvvmH
var sortableCols = [
{
name: 'name',
title: 'Name',
sortable: true
},
{
name: 'instances',
title: 'Instances',
sortable: true,
align: 'center'
},
{
name: 'cpu',
title: 'CPU',
sortable: true,
align: 'right'
},
{
name: 'synergy',
title: 'Synergy',
align: 'left'
}
]
TABS IN BOOTSTRAP
<div role="tabpanel">
!
<!-- Nav tabs -->
<ul class="nav nav-tabs" role="tablist">
<li role="presentation" class=“active">
<a href="#home" aria-controls="home" role="tab" data-toggle=“tab">Home</a>
</li>
<li role=“presentation">
<a href="#profile" aria-controls="profile" role="tab" data-toggle=“tab”>
Profile</a>
</li>
</ul>
!
<!-- Tab panes -->
<div class="tab-content">
<div role="tabpanel" class="tab-pane active" id="home">...</div>
<div role="tabpanel" class="tab-pane" id="profile">...</div>
</div>
!
</div>
TABS IN REACT
<SimpleTabs defaultActiveKey={1}>
<Tab eventKey={1} tab="Home">
...
</Tab>
<Tab eventKey={2} tab="Profile">
...
</Tab>
</SimpleTabs>
https://www.flickr.com/photos/wscullin/3770015991/in/photolist-6K9jpH-4mbNmG-4Cryx-6K9jC4-9hYhWK-dexZ3L-bpV8UA-6K9jb8-2aRBU9-c2mfZu-8desRa-ntKGaS-8ZxBba-7RVQRi-7AbLTM-dMTqW3-4866mH-rjNaZL-7MP9RU-
dhfQ5N-rfCB9g-nBshnQ-7Xn7f-87asnj-84R7FU-sepy36-dtEmrp-rhsh7A-hVCY8u-4m7NmB-qqiNK6-bMLUPp-qY4LbS-q1prK-5WoP4f-Ftxe-4mbHVY-jB4t16-5qgm94-5WjwED-7vS6fV-5WoP4N-biVihz-9KsFUo-9KpQVF-9KpQMz-
IT’S A DESIGN DECISION
each component is different
KEEP LOOPING BACK
change the interface until it works well
GOOD DESIGN PRINCIPLES
❖ Many drawers -Tom O	

❖ Set good defaults	

❖ User shouldn’t need to understand CSS to use it	

❖ Make tiny components with one job (same as CSS)	

❖ Allow flexibility	

❖ Prefer a complex implementation over a complex interface
what has worked for us
WHO ARE YOUR USERS?
component creators and maintainers, contributors, developers
building features, actual product users
https://www.flickr.com/photos/fabiansociety/16300828766/in/photolist-qQs1tQ-qAa8pJ-pVJmYw-qxNcH4-qAaDuJ-qSHJsr-5SDe5H-josG7R-dxrFDm-e6S4TN-fddCLi-po7JuN-d21PZN-ax7LAK-qBLEie-dEMphp-byfU17-nPjAPc-eZ7ooX-
ctHbf5-g5QFS-naVVhZ-cFgo6s-akEb2Q-qUQi3c-aGJ83i-627cGv-aRFFNx-nSyXpr-dyXFU7-aupkvk-buYgB2-nj7Xyv-jHSXR5-9eAqzK-eNqYdm-a4GaUk-qiFrdF-dy1QsG-bPqzrk-9dEUm7-n7cmgE-gJNeKz-nigszh-mi4QjT-s76Yxa-
USE ALL THE TOOLS IN
YOUR TOOLBOX
❖ Elements (built in and custom)	

❖ Attributes (simple and objects)	

❖ JSON	

❖ Children
styleguide.pivotal.io
WE OPEN SOURCED
EVERYTHING
Please do give us feedback 	

npm: https://www.npmjs.com/search?q=pui 	

github: github.com/pivotal-cf/pivotal-ui
THANK YOU!
@stubbornella

Building the Media Block in ReactJS

  • 1.
    BUILDING THE MEDIA BLOCKIN REACTJS the API is an interface that needs to be designed https://www.flickr.com/photos/darpi/212323100/in/photolist-jLdg7-4zEiwa-nwFCR-cZVtBE-4NHtnv-7daytd-pce3y-4NH3fh-5TLS72-58aMX7-58aMVN-a3826y-gVDVKr-8DRhUB-nEdkNf-6tnApQ- fqJRqv-4NMHx7-7fUPoM-cNu2W-8etirE-o7PZA-wsB4L-7ABatu-8LyEF5-7iEjwY-3faCd1-9Gn1fF-4qYRms-JUKbE-7B97bb-69Uer5-5DQMzG-f4ZgsG-7TvUJp-5zyhEh-65naZh-nBkNs-5eCcAF-sErjv-4ePHGY-6kV1Q4- nxWYX-dpGR5-55vgqd-5scyot-5t7uJJ-nLQn5y-9Njbu-79B4aw
  • 2.
    @STUBBORNELLA twitter really isthe best way to reach me…
  • 3.
    WHAT WILL WECOVER? ❖ What is a media block? ❖ Why use ReactJS ❖ Making a media block in ReactJS
  • 4.
    WHAT IS THEMEDIA BLOCK? let’s look at an example from Facebook
  • 5.
  • 6.
    ALL OF THESEARE THE SAME OBJECT
  • 7.
    WHAT DO WEKNOW? ! ❖ Can be nested ❖ Optional right button ❖ Must clearfix
  • 8.
    WHAT DO WEKNOW? ! ❖ Allows top, middle, or bottom alignment
  • 9.
    WHAT DON’T WEKNOW? ❖ Image width and decoration vary ❖ Right content is unknown ❖ Width unknown
  • 10.
    A FEW LINESOF HTML... <div class="media attribution"> <a href="http://twitter.com/stubbornella" class="img"> <img src="mini.jpg" alt="Stubbornella" /> </a> <div class="bd">@Stubbornella 14 minutes ago</div> </div>
  • 11.
    4 LINES OFCSS... _
  • 13.
    I <3 HTML,WHY USE REACT? ❖ html consistency (modal debugging) ❖ smaller api (fewer breaking changes) ❖ don’t need to go everywhere a component was used to update the dom if it changes ❖ lightning fast dom updates when data changes ❖ not managing those updates manually ❖ simpler APIs (tabs example)
  • 14.
    I CAN’T COVER EVERYTHING So doRyan Florence’s tutorials: https://github.com/ ryanflorence/react-training/
  • 15.
  • 16.
    WHAT ARE THEELEMENTS OF A REACT INTERFACE ❖ Elements ❖ Attributes ❖ Nested children ❖ Data Sounds a lot like html, right?
  • 17.
    HOW DO YOUMAKE A MEDIA COMPONENT? in React Code var Media = React.createClass({ ! });
  • 18.
    SO THEN, HOWWOULD YOU USE IT? It’s kind of like HTML, it’s called jsx <Media> My very first React component! </Media>
  • 19.
    BUT, WE NEEDTO EXPORT the Media component, so it can be used in other files module.exports = { Media: Media };
  • 20.
    DESCRIBE IT WITHA RENDER FUNCTION This tells the browser what HTML to render. var Media = React.createClass({ render: function () { return ( <p> {this.props.children} </p> ); } }); just render a paragraph, for now tell React where to render children
  • 21.
  • 22.
    LET’S TRY IT! Sweet,this is gonna be rad. <Media> This text is our component’s children! </Media> ! ! ! ! <p> This text is our component’s children! </p>
  • 23.
    LET’S TRY IT! Sweet,this is gonna be rad. <Media> This text is our component’s children! </Media> ! ! ! ! <p> This text is our component’s children! </p> When React renders that component we get this html
  • 24.
    LET’S TRY IT! Sweet,this is gonna be rad. <Media> This text is our component’s children! </Media> ! ! ! ! <p> This text is our component’s children! </p> {this.props.children} When React renders that component we get this html
  • 25.
    NOT VERY USEFUL,RIGHT? You'd never use react to render a simple paragraph because it already understands <p> tags, you can just use them!
  • 26.
    LET’S BUILD ANACTUAL MEDIA BLOCK Step 1:Add the left image
  • 27.
    SO, WHAT DIDWE TRY FIRST? https://www.flickr.com/photos/mstewartphotography/6195718653/in/photolist-aruFip-3Ym2sP-d5ipmU-61ivfM-2SmfSo-eMWyyv-7Tx3yN-p7xVZN-5LExX5-dG1RK2-86LsMW-6TDV5Y-9isMj1-cJuUm-4v2NE- amKvge-61TfaY-61PcSp-61nGEd-86FasK-qrz8VS-4bGoKp-77DPsN-7NeZKn-botCkn-8vpoEE-oTAKWV-5Sz1Fv-a5oF29-86Hf14-aS9vmZ-a8M5q6-a8Mh8k-7AKzoA-86HcPz-61HM17-7AFRcK-a8LXht-5c5LvE-a8LZXX-61Hb8A- fJgHuw-86LhDq-86Lmch-3jzdZ-5mYENE-8UMWoM-bx1iUr-p9jsSa-a865Ji https://www.flickr.com/photos/mstewartphotography/6195718653/in/photolist-aruFip-3Ym2sP-d5ipmU-61ivfM-2SmfSo-eMWyyv-7Tx3yN-p7xVZN-5LExX5-dG1RK2-86LsMW-6TDV5Y-9isMj1-cJuUm-4v2NE- amKvge-61TfaY-61PcSp-61nGEd-86FasK-qrz8VS-4bGoKp-77DPsN-7NeZKn-botCkn-8vpoEE-oTAKWV-5Sz1Fv-a5oF29-86Hf14-aS9vmZ-a8M5q6-a8Mh8k-7AKzoA-86HcPz-61HM17-7AFRcK-a8LXht-5c5LvE-a8LZXX-61Hb8A- fJgHuw-86LhDq-86Lmch-3jzdZ-5mYENE-8UMWoM-bx1iUr-p9jsSa-a865Ji
  • 28.
    TONS OF ATTRIBUTES Whatcould go wrong? ;) https://www.flickr.com/photos/ilo_oli/5856288807/in/photolist-jpnSsc-bp1mTF-iC3JNn-feu2hV-feJdEw-dCsd6V-aQmwUk-qJvwYx-qKHp7N-qKJtpL-pMFnAC-9XxWkr-qKJEV1-q6hte9-qZZXHG-q6hp8d-qKHchA-qKJt8U-bp1mv2- b6LSWT-bKfSon-kxWCNt-b6LNN8-b8Vpk6-ehScwd-c5CMgq-qKJcqw-r3iaXK-pMieGe-9ZUFNi-aD4zaE-fDwLBF-9Vv1CF-kzarYi-9ovVLy-rVLApS-fDwKki-b5sxAg-fskG7P-bUUme1-bKgdD6-c5CMiW-a1wsSP-4u7U5a-dtv95k-dtvKP6- dtBtwJ-dtvrRR-dtBm2s-abcAqR
  • 29.
    CREATE A SOURCE ATTRIBUTE We’lluse it in our render function to set the src of the image <Media leftImageSource='http://placehold.it/50x50'> Media block content </Media> React props are a lot like HTML attributes
  • 30.
    BUT WAIT, THEIMAGE CAN BE A LINK Sometimes…
  • 31.
    SO, LET’S ADDAN HREF ATTRIBUTE <Media leftImageSource='http://placehold.it/50x50' leftImageHref='http://www.google.com'> Media block content </Media> Our render function will make this into a link wrapper (if it is set)
  • 32.
    THE IMAGE CANBE VERTICALLY ALIGNED
  • 33.
  • 34.
  • 35.
    WE NEED ANALT ATTRIBUTE <Media leftImageSource='http://placehold.it/50x50' leftImageHref='http://www.google.com' leftImageAlignment='middle' leftImageAlt="profile photo"> Media block content </Media> Our render function will make this into an alt attribute on the <img> tag
  • 36.
  • 37.
    WE NEED AHEIGHT AND WIDTH <Media leftImageSource='http://placehold.it/50x50' leftImageHref='http://www.google.com' leftImageAlignment='middle' leftImageAlt="profile photo" leftImageHeight="50px" leftImageWidth="50px"> Media block content </Media> Explicit height and width allow the browser to do a single rendering/painting pass
  • 38.
    SET THE GUTTERBETWEEN IMAGE AND CONTENT with the spacing attribute <Media leftImageSource='http://placehold.it/50x50' leftImageHref='http://www.google.com' leftImageAlignment='middle' leftImageAlt="profile photo" leftImageHeight="50px" leftImageWidth="50px" leftImageSpacing="medium"> Media block content </Media> For when the 10px default spacing isn’t right, like a tiny icon with text
  • 39.
    PROPERTIES OF THEMEDIA rather than its images
  • 40.
    FOR EXAMPLE, IT’S RESPONSIVE viathe stacksize (breakpoint) attribute <Media leftImageSource='http://placehold.it/50x50' leftImageHref='http://www.google.com' leftImageAlignment='middle' leftImageAlt="profile photo" leftImageHeight="50px" leftImageWidth="50px" leftImageSpacing="medium" stackSize='medium'> Media block content </Media> stack size puts the image above the text at the breakpoint
  • 41.
    THIS IS GETTING OUTOF HAND! But we forgot something, the media block can have a right image
  • 42.
    ADD THE RIGHTIMAGE PROPERTIES This is out of control, we are going the wrong way! <Media leftImageSource='http://placehold.it/50x50' leftImageHref='http://www.google.com' leftImageAlignment='middle' leftImageAlt="profile photo" leftImageHeight="50px" leftImageWidth="50px" rightImageSource='http://placehold.it/50x50' rightImageHref='http://www.google.com' rightImageAlignment='middle' rightImageAlt="profile photo" rightImageHeight="50px" rightImageWidth="50px" rightImageSpacing="medium" bodyAlignment='middle' stackSize='medium'> Media block content </Media> right image props
  • 43.
    PROS/CONS ❖ It’s veryexplicit, we know what each thing does What works? ❖ We're basically recreating html in React, yuck! (we shouldn’t make a new different alt attribute! ❖ We have image properties and media properties all mixed up ❖ We have too many properties What doesn’t work?
  • 44.
    SO, WHAT DIDWE TRY NEXT? https://www.flickr.com/photos/mstewartphotography/6195718653/in/photolist-aruFip-3Ym2sP-d5ipmU-61ivfM-2SmfSo-eMWyyv-7Tx3yN-p7xVZN-5LExX5-dG1RK2-86LsMW-6TDV5Y-9isMj1-cJuUm-4v2NE- amKvge-61TfaY-61PcSp-61nGEd-86FasK-qrz8VS-4bGoKp-77DPsN-7NeZKn-botCkn-8vpoEE-oTAKWV-5Sz1Fv-a5oF29-86Hf14-aS9vmZ-a8M5q6-a8Mh8k-7AKzoA-86HcPz-61HM17-7AFRcK-a8LXht-5c5LvE-a8LZXX-61Hb8A- fJgHuw-86LhDq-86Lmch-3jzdZ-5mYENE-8UMWoM-bx1iUr-p9jsSa-a865Ji https://www.flickr.com/photos/mstewartphotography/6195718653/in/photolist-aruFip-3Ym2sP-d5ipmU-61ivfM-2SmfSo-eMWyyv-7Tx3yN-p7xVZN-5LExX5-dG1RK2-86LsMW-6TDV5Y-9isMj1-cJuUm-4v2NE- amKvge-61TfaY-61PcSp-61nGEd-86FasK-qrz8VS-4bGoKp-77DPsN-7NeZKn-botCkn-8vpoEE-oTAKWV-5Sz1Fv-a5oF29-86Hf14-aS9vmZ-a8M5q6-a8Mh8k-7AKzoA-86HcPz-61HM17-7AFRcK-a8LXht-5c5LvE-a8LZXX-61Hb8A- fJgHuw-86LhDq-86Lmch-3jzdZ-5mYENE-8UMWoM-bx1iUr-p9jsSa-a865Ji
  • 45.
    JSON ALL THETHINGS https://www.flickr.com/photos/bike/4797449644/in/photolist-8iWbD3-5HPWhF-QyKg5-eVYyjt-3meRNg-5HPW94-4HwYMz-utah8-3qvXS-aqsJtx-eyQK4T-42P9p1-7Th995-5oKgDS-5mJEJe-9bt9At-4zbwwo-8vDr8Z-7konhy- BhrJ9-5zHQ7E-bobveq-DmrMg-3qvNs-5HPW1P-qtLJmp-5ZCPcW-9QuNBj-5HUdgS-9thCcq-6FmTKV-7QgAua-6DZyzu-gkukag-apwsgp-8hWccC-4U7EX6-pfaKPb-hvM3q-asXuSH-at18RL-asXuDV-asXuC4-9ys6M7-phFVSp- dkdPkb-86toqn-dzVg-zVaLA-cDsK7N
  • 46.
    OUR IMAGES ASJSON kinda weird, but it might work… var images = [ { "src": "http://placehold.it/50x50", "href": "http://www.google.com", "alignment": "middle", "alt": "profile photo", "height": "50px", "width": "50px" }, { "src": "http://placehold.it/50x50", "href": "http://www.google.com", "alignment": "middle", "alt": "profile photo", "height": "50px", "width": "50px" } ];
  • 47.
    JSON IN THEMEDIA passed in as another property <Media images={images} bodyAlignment='middle' stackSize='medium'> Media block content </Media>
  • 48.
    JSON IN THEMEDIA passed in as another property <Media images={images} bodyAlignment='middle' stackSize='medium'> Media block content </Media> {curly braces} mean it’s a JavaScript variable rather than a string
  • 49.
    JSON IN THEMEDIA passed in as another property <Media images={images} bodyAlignment='middle' stackSize='medium'> Media block content </Media> json goes into the images attribute {curly braces} mean it’s a JavaScript variable rather than a string
  • 50.
    What works? Whatdoesn’t work? PROS/CONS ❖ abstraction of passing in JSON means all the code isn't in the same place ❖ weird to have JSON in the middle of what looks like markup ❖ still reinventing html attributes of an <img> tag ❖ cleaner separation of concerns (media takes care of media stuff, rather than the properties of its children)
  • 51.
    WHAT DID WEDO NEXT? https://www.flickr.com/photos/mstewartphotography/6195718653/in/photolist-aruFip-3Ym2sP-d5ipmU-61ivfM-2SmfSo-eMWyyv-7Tx3yN-p7xVZN-5LExX5-dG1RK2-86LsMW-6TDV5Y-9isMj1-cJuUm-4v2NE- amKvge-61TfaY-61PcSp-61nGEd-86FasK-qrz8VS-4bGoKp-77DPsN-7NeZKn-botCkn-8vpoEE-oTAKWV-5Sz1Fv-a5oF29-86Hf14-aS9vmZ-a8M5q6-a8Mh8k-7AKzoA-86HcPz-61HM17-7AFRcK-a8LXht-5c5LvE-a8LZXX-61Hb8A- fJgHuw-86LhDq-86Lmch-3jzdZ-5mYENE-8UMWoM-bx1iUr-p9jsSa-a865Ji https://www.flickr.com/photos/mstewartphotography/6195718653/in/photolist-aruFip-3Ym2sP-d5ipmU-61ivfM-2SmfSo-eMWyyv-7Tx3yN-p7xVZN-5LExX5-dG1RK2-86LsMW-6TDV5Y-9isMj1-cJuUm-4v2NE- amKvge-61TfaY-61PcSp-61nGEd-86FasK-qrz8VS-4bGoKp-77DPsN-7NeZKn-botCkn-8vpoEE-oTAKWV-5Sz1Fv-a5oF29-86Hf14-aS9vmZ-a8M5q6-a8Mh8k-7AKzoA-86HcPz-61HM17-7AFRcK-a8LXht-5c5LvE-a8LZXX-61Hb8A- fJgHuw-86LhDq-86Lmch-3jzdZ-5mYENE-8UMWoM-bx1iUr-p9jsSa-a865Ji
  • 52.
    PARSING CHILDREN We decidedto try including the images as children https://www.flickr.com/photos/i-am-mclovin/16535518502/in/photolist-rcbRyA-nshV4n-eAaqTz-bCfUFZ-jH4tBF-pctQQD-qNmfZS-eT3GMZ-bTJsji-N8LkW-iCxgoA-7JDTp2-mPGu7V-dV4m7G-igpkaV-dRobZv-mnUN9i-igoYgJ-bCzBBi- f9tdxa-oMiWTE-b6LMzz-rcTY6S-dYq12b-qUh6hV-f6oFCx-pmwC9Z-hNLucH-moYnBt-6uGwja-aRrBm4-mPGGDB-igp6YC-f8b3QR-igpkXB-igoY3C-o62zzh-iC3JNn-9217QQ-D3JPG-pcHyUy-pprMfU-igoJAg-hgRxSL-pqomg9- ahQDpD-4LkbKg-hNLcDy-igoJb8-9STs34
  • 53.
    PARSING CHILDREN better, everythingis normal html! But, it has a few drawbacks <Media> <img src='http://placehold.it/50x50' href='http://www.google.com' alignment='middle' alt="profile photo" height="50px" width="50px" > <p>My media content</p> <img src='http://placehold.it/50x50' href='http://www.google.com' alignment='middle' alt="profile photo" height="50px" width="50px" > </Media>
  • 54.
    What works? Whatdoesn’t work? PROS/CONS ❖ The images and body content need to be in a very particular order, it seems weird to expose that to the user ❖ Violates the "build components you can use without understanding CSS” principle ❖ Normal HTML ❖ Facebook does it this way
  • 55.
    WHAT *ELSE* DOESN’T WORK? ❖We could loop over children and reorder them, but how do we tell the difference between content images and media images? ❖ We were still discovering React, and didn't know how to loop over children yet ❖ React provides handy error messages and property validations. We would lose out on that if we made the images children ❖ Facebook's images aren't optional, so it's a different case
  • 56.
    SO, WHAT DIDWE TRY NEXT? https://www.flickr.com/photos/mstewartphotography/6195718653/in/photolist-aruFip-3Ym2sP-d5ipmU-61ivfM-2SmfSo-eMWyyv-7Tx3yN-p7xVZN-5LExX5-dG1RK2-86LsMW-6TDV5Y-9isMj1-cJuUm-4v2NE- amKvge-61TfaY-61PcSp-61nGEd-86FasK-qrz8VS-4bGoKp-77DPsN-7NeZKn-botCkn-8vpoEE-oTAKWV-5Sz1Fv-a5oF29-86Hf14-aS9vmZ-a8M5q6-a8Mh8k-7AKzoA-86HcPz-61HM17-7AFRcK-a8LXht-5c5LvE-a8LZXX-61Hb8A- fJgHuw-86LhDq-86Lmch-3jzdZ-5mYENE-8UMWoM-bx1iUr-p9jsSa-a865Ji https://www.flickr.com/photos/mstewartphotography/6195718653/in/photolist-aruFip-3Ym2sP-d5ipmU-61ivfM-2SmfSo-eMWyyv-7Tx3yN-p7xVZN-5LExX5-dG1RK2-86LsMW-6TDV5Y-9isMj1-cJuUm-4v2NE- amKvge-61TfaY-61PcSp-61nGEd-86FasK-qrz8VS-4bGoKp-77DPsN-7NeZKn-botCkn-8vpoEE-oTAKWV-5Sz1Fv-a5oF29-86Hf14-aS9vmZ-a8M5q6-a8Mh8k-7AKzoA-86HcPz-61HM17-7AFRcK-a8LXht-5c5LvE-a8LZXX-61Hb8A- fJgHuw-86LhDq-86Lmch-3jzdZ-5mYENE-8UMWoM-bx1iUr-p9jsSa-a865Ji
  • 57.
    REACT BUILT-IN <IMG> COMPONENT Inreact, everything is a component.
  • 58.
    FIRST, WE MAKEOUR IMAGES var leftImage = <img src='http://placehold.it/ 50x50' href='http://www.google.com' alignment='middle' alt="profile photo" height="50px" width="50px">; ! var rightImage = <img src='http://placehold.it/ 50x50' href='http://www.google.com' alignment='middle' alt="profile photo" height="50px" width=“50px">;
  • 59.
    NEXT, WE MAKEOUR MEDIA OBJECT this looks similar to the JSON example <Media leftImage={leftImage} rightImage={rightImage} bodyAlignment='middle' stackSize='medium'> Media block content </Media>
  • 60.
    NEXT, WE MAKEOUR MEDIA OBJECT this looks similar to the JSON example <Media leftImage={leftImage} rightImage={rightImage} bodyAlignment='middle' stackSize='medium'> Media block content </Media> left and right images are passed into attributes
  • 61.
    YOU CAN EVENWRITE IT like this if you really want to <Media leftImage={<img src='http://placehold.it/50x50' href='http://www.google.com' alignment='middle' alt="profile photo" height="50px" width="50px">} bodyAlignment='middle' stackSize='medium'> Media block content </Media> image component directly in the attribute property
  • 62.
    What works? Whatdoesn’t work? PROS/CONS ❖ HTML inside an attribute (in the latter example) is a bit odd, though it does have advantages. ❖ React passes default html attributes in to the resulting img tag, so we don't have to do anything special with height, width, src, aria and alt. ❖ We separate concerns and the image takes care of it's own properties ❖ No need to parse content
  • 63.
    WHAT *ELSE* DOESN’T WORK? ❖href will be passed through. So our image will have an href attribute. I like clean html, and that feels weird to me! <div class="media"> <a href="styleguide.pivotal.io"> <img href="styleguide.pivotal.io" /> ... Yuck!
  • 64.
    WE CONSIDERED GOING BACKTO PROPERTIES… but decided we should make our own <img> wrapper <Media leftImageHref="styleguide.pivotal.io"> to property or not to property?
  • 65.
    SO, WHAT DIDWE TRY NEXT? https://www.flickr.com/photos/mstewartphotography/6195718653/in/photolist-aruFip-3Ym2sP-d5ipmU-61ivfM-2SmfSo-eMWyyv-7Tx3yN-p7xVZN-5LExX5-dG1RK2-86LsMW-6TDV5Y-9isMj1-cJuUm-4v2NE- amKvge-61TfaY-61PcSp-61nGEd-86FasK-qrz8VS-4bGoKp-77DPsN-7NeZKn-botCkn-8vpoEE-oTAKWV-5Sz1Fv-a5oF29-86Hf14-aS9vmZ-a8M5q6-a8Mh8k-7AKzoA-86HcPz-61HM17-7AFRcK-a8LXht-5c5LvE-a8LZXX-61Hb8A- fJgHuw-86LhDq-86Lmch-3jzdZ-5mYENE-8UMWoM-bx1iUr-p9jsSa-a865Ji https://www.flickr.com/photos/mstewartphotography/6195718653/in/photolist-aruFip-3Ym2sP-d5ipmU-61ivfM-2SmfSo-eMWyyv-7Tx3yN-p7xVZN-5LExX5-dG1RK2-86LsMW-6TDV5Y-9isMj1-cJuUm-4v2NE- amKvge-61TfaY-61PcSp-61nGEd-86FasK-qrz8VS-4bGoKp-77DPsN-7NeZKn-botCkn-8vpoEE-oTAKWV-5Sz1Fv-a5oF29-86Hf14-aS9vmZ-a8M5q6-a8Mh8k-7AKzoA-86HcPz-61HM17-7AFRcK-a8LXht-5c5LvE-a8LZXX-61Hb8A- fJgHuw-86LhDq-86Lmch-3jzdZ-5mYENE-8UMWoM-bx1iUr-p9jsSa-a865Ji
  • 66.
    CUSTOM IMAGE COMPONENT And anothercomponent was born… https://www.flickr.com/photos/eltonharding/522073772/in/photolist-N8LkW-dLnt39-dsdYRQ-qcf3KQ-rgojpc-dsdWxA-dRxje9-iAgtmB-aaTYBU-mgGFrk-d3TMAf-opZhPw-nbi6ut-gMDt1W-adGAGZ-j8HqHK-gAt6ec-mc944B- nEMWpG-oQkVQ4-qR9xvi-gSVfC5-oUurRb-9jGTJD-nWUZza-e5NeHJ-aTYLCT-dTTRha-rp3zLC-qn7i8t-hQxDrG-9qcih5-sn5TTi-9aQfXm-nsgfeC-niFxPL-dRxjy7-9Ry7C3-p8VRa4-noA5cx-oovJdV-kLSLxL-dpgFWM-rhZ9Ri- dRxkm3-9qResk-kGDeJb-bprRNw-oCC5tt-oCX7iY
  • 67.
    GOAL: OUTPUTS ASIMPLE <IMG> TAG but won't pass through attributes that don't make sense like href
  • 68.
    STEP 1: CREATETHE IMAGE COMPONENT var Image = React.createClass({ ! });
  • 69.
    STEP 2: EXPORTTHE IMAGE the same way we did the Media component module.exports = {Image};
  • 70.
    STEP 3: GETITS PROPERTIES and render an image var Image = React.createClass({ render() { var {href, src, children, className, ...other} = this.props; ! var image = <img {...other} src={src} className={classes}>; ! return href ? <a {...{href}}>{image}</a> : image; } });
  • 71.
    STEP 3: GETITS PROPERTIES and render an image var Image = React.createClass({ render() { var {href, src, children, className, ...other} = this.props; ! var image = <img {...other} src={src} className={classes}>; ! return href ? <a {...{href}}>{image}</a> : image; } }); get the properties we need
  • 72.
    STEP 3: GETITS PROPERTIES and render an image var Image = React.createClass({ render() { var {href, src, children, className, ...other} = this.props; ! var image = <img {...other} src={src} className={classes}>; ! return href ? <a {...{href}}>{image}</a> : image; } }); get the properties we need build the image from our properties
  • 73.
    STEP 3: GETITS PROPERTIES and render an image var Image = React.createClass({ render() { var {href, src, children, className, ...other} = this.props; ! var image = <img {...other} src={src} className={classes}>; ! return href ? <a {...{href}}>{image}</a> : image; } }); get the properties we need build the image from our properties if we have a link, wrap the image in an <a> tag
  • 74.
    STEP 4: MAKEIT RESPONSIVE by handling the responsive boolean var Image = React.createClass({ render() { var {responsive, href, src, children, className, ...other} = this.props; ! var image = <img {...other} src={src}>; return href ? <a {...{href}}>{image}</a> : image; } });
  • 75.
    STEP 4: MAKEIT RESPONSIVE by handling the responsive boolean var Image = React.createClass({ render() { var {responsive, href, src, children, className, ...other} = this.props; ! var image = <img {...other} src={src}>; return href ? <a {...{href}}>{image}</a> : image; } }); get the responsive property
  • 76.
    STEP 4: MAKEIT RESPONSIVE and setting the img-responsive class if the boolean is true var Image = React.createClass({ render() { var {responsive, href, src, children, className, ...other} = this.props; ! var classes = classnames({'img-responsive': responsive}, className); ! ! ! ! ! ! ! var image = <img {...other} src={src} className={classes}>{children}</img>; return href ? <a {...{href}}>{image}</a> : image; } });
  • 77.
    STEP 4: MAKEIT RESPONSIVE and setting the img-responsive class if the boolean is true var Image = React.createClass({ render() { var {responsive, href, src, children, className, ...other} = this.props; ! var classes = classnames({'img-responsive': responsive}, className); ! ! ! ! ! ! ! var image = <img {...other} src={src} className={classes}>{children}</img>; return href ? <a {...{href}}>{image}</a> : image; } }); add this class if this evaluates to true
  • 78.
    STEP 4: MAKEIT RESPONSIVE and setting the img-responsive class if the boolean is true var Image = React.createClass({ render() { var {responsive, href, src, children, className, ...other} = this.props; ! var classes = classnames({'img-responsive': responsive}, className); ! ! ! ! ! ! ! var image = <img {...other} src={src} className={classes}>{children}</img>; return href ? <a {...{href}}>{image}</a> : image; } }); add this class if this evaluates to true then, put the class on the image
  • 79.
    STEP 5: VALIDATE PROPERTIES varImage = React.createClass({ propTypes: { responsive: types.bool, href: types.string, src: types.string.isRequired }, ! render() { var {responsive, href, src, children, className, ...other} = this.props; var classes = classnames({'img-responsive': responsive}, className); ! var image = <img {...other} src={src} className={classes}>{children}</img>; return href ? <a {...{href}}>{image}</a> : image; } });
  • 80.
    STEP 5: VALIDATE PROPERTIES varImage = React.createClass({ propTypes: { responsive: types.bool, href: types.string, src: types.string.isRequired }, ! render() { var {responsive, href, src, children, className, ...other} = this.props; var classes = classnames({'img-responsive': responsive}, className); ! var image = <img {...other} src={src} className={classes}>{children}</img>; return href ? <a {...{href}}>{image}</a> : image; } }); responsive has to be true or false
  • 81.
    STEP 5: VALIDATE PROPERTIES varImage = React.createClass({ propTypes: { responsive: types.bool, href: types.string, src: types.string.isRequired }, ! render() { var {responsive, href, src, children, className, ...other} = this.props; var classes = classnames({'img-responsive': responsive}, className); ! var image = <img {...other} src={src} className={classes}>{children}</img>; return href ? <a {...{href}}>{image}</a> : image; } });
  • 82.
    STEP 5: VALIDATE PROPERTIES varImage = React.createClass({ propTypes: { responsive: types.bool, href: types.string, src: types.string.isRequired }, ! render() { var {responsive, href, src, children, className, ...other} = this.props; var classes = classnames({'img-responsive': responsive}, className); ! var image = <img {...other} src={src} className={classes}>{children}</img>; return href ? <a {...{href}}>{image}</a> : image; } }); the href is a string
  • 83.
    STEP 5: VALIDATE PROPERTIES varImage = React.createClass({ propTypes: { responsive: types.bool, href: types.string, src: types.string.isRequired }, ! render() { var {responsive, href, src, children, className, ...other} = this.props; var classes = classnames({'img-responsive': responsive}, className); ! var image = <img {...other} src={src} className={classes}>{children}</img>; return href ? <a {...{href}}>{image}</a> : image; } });
  • 84.
    STEP 5: VALIDATE PROPERTIES varImage = React.createClass({ propTypes: { responsive: types.bool, href: types.string, src: types.string.isRequired }, ! render() { var {responsive, href, src, children, className, ...other} = this.props; var classes = classnames({'img-responsive': responsive}, className); ! var image = <img {...other} src={src} className={classes}>{children}</img>; return href ? <a {...{href}}>{image}</a> : image; } }); src is a string and required
  • 85.
    STEP 5: VALIDATE PROPERTIES varImage = React.createClass({ propTypes: { responsive: types.bool, href: types.string, src: types.string.isRequired }, ! render() { var {responsive, href, src, children, className, ...other} = this.props; var classes = classnames({'img-responsive': responsive}, className); ! var image = <img {...other} src={src} className={classes}>{children}</img>; return href ? <a {...{href}}>{image}</a> : image; } });
  • 86.
    STEP 5: VALIDATE PROPERTIES varImage = React.createClass({ propTypes: { responsive: types.bool, href: types.string, src: types.string.isRequired }, ! render() { var {responsive, href, src, children, className, ...other} = this.props; var classes = classnames({'img-responsive': responsive}, className); ! var image = <img {...other} src={src} className={classes}>{children}</img>; return href ? <a {...{href}}>{image}</a> : image; } });
  • 87.
    OUR “AH-HA” MOMENT Usersare still needing to specify too many things to get this component to work, they might as well just write html!
  • 88.
    SO, WHAT DIDWE DO NEXT? https://www.flickr.com/photos/mstewartphotography/6195718653/in/photolist-aruFip-3Ym2sP-d5ipmU-61ivfM-2SmfSo-eMWyyv-7Tx3yN-p7xVZN-5LExX5-dG1RK2-86LsMW-6TDV5Y-9isMj1-cJuUm-4v2NE- amKvge-61TfaY-61PcSp-61nGEd-86FasK-qrz8VS-4bGoKp-77DPsN-7NeZKn-botCkn-8vpoEE-oTAKWV-5Sz1Fv-a5oF29-86Hf14-aS9vmZ-a8M5q6-a8Mh8k-7AKzoA-86HcPz-61HM17-7AFRcK-a8LXht-5c5LvE-a8LZXX-61Hb8A- fJgHuw-86LhDq-86Lmch-3jzdZ-5mYENE-8UMWoM-bx1iUr-p9jsSa-a865Ji https://www.flickr.com/photos/mstewartphotography/6195718653/in/photolist-aruFip-3Ym2sP-d5ipmU-61ivfM-2SmfSo-eMWyyv-7Tx3yN-p7xVZN-5LExX5-dG1RK2-86LsMW-6TDV5Y-9isMj1-cJuUm-4v2NE- amKvge-61TfaY-61PcSp-61nGEd-86FasK-qrz8VS-4bGoKp-77DPsN-7NeZKn-botCkn-8vpoEE-oTAKWV-5Sz1Fv-a5oF29-86Hf14-aS9vmZ-a8M5q6-a8Mh8k-7AKzoA-86HcPz-61HM17-7AFRcK-a8LXht-5c5LvE-a8LZXX-61Hb8A- fJgHuw-86LhDq-86Lmch-3jzdZ-5mYENE-8UMWoM-bx1iUr-p9jsSa-a865Ji
  • 89.
    ELEMENTS FTW we cansimplify our interface further https://www.flickr.com/photos/rejik/14681743931/in/photolist-onnLY4-nPYfhm-ed6PWM-bvWmjA-mMGE1V-j88ToM-ngTbpk-nUg38a-9n1hgv-4KZr2Z-nucMef-dd5exw-9eyaqy-8QWK1i-eaTuFL-4RbvFX-7kiwo3-7NqP2a-4R1KYB- mZEx1J-5iV12q-39v9f8-bqt2rx-7zvWs-9eyamJ-7JKZAh-hiwiDa-poG8fx-ehZRGj-684GeT-pPeQGL-efRP9f-icXKJY-aNxWqT-9niyKk-ouarpw-bmC5SK-7s5DNV-bqt3F8-bqsZ24-mZCLWp-86YqXk-e6ERub-bqtEL8-8K3pJf- kik4tg-8yYivi-8fi3Ep-dVohpu-fzmggH https://www.flickr.com/photos/rejik/14681743931/in/photolist-onnLY4-nPYfhm-ed6PWM-bvWmjA-mMGE1V-j88ToM-ngTbpk-nUg38a-9n1hgv-4KZr2Z-nucMef-dd5exw-9eyaqy-8QWK1i-eaTuFL-4RbvFX-7kiwo3-7NqP2a-4R1KYB- mZEx1J-5iV12q-39v9f8-bqt2rx-7zvWs-9eyamJ-7JKZAh-hiwiDa-poG8fx-ehZRGj-684GeT-pPeQGL-efRP9f-icXKJY-aNxWqT-9niyKk-ouarpw-bmC5SK-7s5DNV-bqt3F8-bqsZ24-mZCLWp-86YqXk-e6ERub-bqtEL8-8K3pJf- kik4tg-8yYivi-8fi3Ep-dVohpu-fzmggH
  • 90.
    DESIGNERS ONLY USE2 KINDS OF ALIGNMENT ❖ Traditional media with everything top aligned ! ! ! ❖ “Flag” component a la Harry Roberts middle aligns
  • 91.
    WE MADE THESETWO USE CASES DEAD SIMPLE ❖ We changed the media component to default to top alignment if nothing else was specified. ❖ We created the <flag> component <Flag leftImage={refreshImage}> refresh </Flag>
  • 92.
    What works? Whatdoesn’t work? PROS/CONS ❖ engineers don't always know what the flag object is, documentation and teaching help ❖ with Flag and Media, we no longer need to specify alignment unless we want something weird
  • 93.
    ARE ANY OFTHESE WRONG? No, absolutely not. https://gist.github.com/stubbornella/e97662e4a197eb9a534a
  • 94.
  • 96.
    var sortableCols =[ { name: 'name', title: 'Name', sortable: true }, { name: 'instances', title: 'Instances', sortable: true, align: 'center' }, { name: 'cpu', title: 'CPU', sortable: true, align: 'right' }, { name: 'synergy', title: 'Synergy', align: 'left' } ]
  • 97.
    TABS IN BOOTSTRAP <divrole="tabpanel"> ! <!-- Nav tabs --> <ul class="nav nav-tabs" role="tablist"> <li role="presentation" class=“active"> <a href="#home" aria-controls="home" role="tab" data-toggle=“tab">Home</a> </li> <li role=“presentation"> <a href="#profile" aria-controls="profile" role="tab" data-toggle=“tab”> Profile</a> </li> </ul> ! <!-- Tab panes --> <div class="tab-content"> <div role="tabpanel" class="tab-pane active" id="home">...</div> <div role="tabpanel" class="tab-pane" id="profile">...</div> </div> ! </div>
  • 98.
    TABS IN REACT <SimpleTabsdefaultActiveKey={1}> <Tab eventKey={1} tab="Home"> ... </Tab> <Tab eventKey={2} tab="Profile"> ... </Tab> </SimpleTabs>
  • 99.
  • 100.
    KEEP LOOPING BACK changethe interface until it works well
  • 101.
    GOOD DESIGN PRINCIPLES ❖Many drawers -Tom O ❖ Set good defaults ❖ User shouldn’t need to understand CSS to use it ❖ Make tiny components with one job (same as CSS) ❖ Allow flexibility ❖ Prefer a complex implementation over a complex interface what has worked for us
  • 102.
    WHO ARE YOURUSERS? component creators and maintainers, contributors, developers building features, actual product users https://www.flickr.com/photos/fabiansociety/16300828766/in/photolist-qQs1tQ-qAa8pJ-pVJmYw-qxNcH4-qAaDuJ-qSHJsr-5SDe5H-josG7R-dxrFDm-e6S4TN-fddCLi-po7JuN-d21PZN-ax7LAK-qBLEie-dEMphp-byfU17-nPjAPc-eZ7ooX- ctHbf5-g5QFS-naVVhZ-cFgo6s-akEb2Q-qUQi3c-aGJ83i-627cGv-aRFFNx-nSyXpr-dyXFU7-aupkvk-buYgB2-nj7Xyv-jHSXR5-9eAqzK-eNqYdm-a4GaUk-qiFrdF-dy1QsG-bPqzrk-9dEUm7-n7cmgE-gJNeKz-nigszh-mi4QjT-s76Yxa-
  • 103.
    USE ALL THETOOLS IN YOUR TOOLBOX ❖ Elements (built in and custom) ❖ Attributes (simple and objects) ❖ JSON ❖ Children
  • 105.
  • 106.
    WE OPEN SOURCED EVERYTHING Pleasedo give us feedback npm: https://www.npmjs.com/search?q=pui github: github.com/pivotal-cf/pivotal-ui
  • 107.