Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Building the Media Block in ReactJS

Building the Media Block in ReactJS

Your component API is an interface that needs designing.

Nicole Sullivan

June 09, 2015
Tweet

Other Decks in Technology

Transcript

  1. 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

    View full-size slide

  2. @STUBBORNELLA
    twitter really is the best way to reach me…

    View full-size slide

  3. WHAT WILL WE COVER?
    ❖ What is a media block?

    ❖ Why use ReactJS

    ❖ Making a media block in ReactJS

    View full-size slide

  4. WHAT IS THE MEDIA
    BLOCK?
    let’s look at an example from Facebook

    View full-size slide

  5. MEDIA BLOCK EXAMPLE

    View full-size slide

  6. ALL OF THESE ARE THE
    SAME OBJECT

    View full-size slide

  7. WHAT DO WE KNOW?
    !
    ❖ Can be nested

    ❖ Optional right button

    ❖ Must clearfix

    View full-size slide

  8. WHAT DO WE KNOW?
    !
    ❖ Allows top, middle, or
    bottom alignment

    View full-size slide

  9. WHAT DON’T WE KNOW?
    ❖ Image width and decoration vary

    ❖ Right content is unknown

    ❖ Width unknown

    View full-size slide

  10. A FEW LINES OF HTML...




    @Stubbornella 14 minutes ago

    View full-size slide

  11. 4 LINES OF CSS...
    _

    View full-size slide

  12. 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)

    View full-size slide

  13. I CAN’T
    COVER
    EVERYTHING
    So do Ryan Florence’s
    tutorials:

    https://github.com/
    ryanflorence/react-training/

    View full-size slide

  14. 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

    View full-size slide

  15. WHAT ARE THE ELEMENTS
    OF A REACT INTERFACE
    ❖ Elements

    ❖ Attributes

    ❖ Nested children

    ❖ Data
    Sounds a lot like html, right?

    View full-size slide

  16. HOW DO YOU MAKE A
    MEDIA COMPONENT?
    in React
    Code
    var Media = React.createClass({
    !
    });

    View full-size slide

  17. SO THEN, HOW WOULD
    YOU USE IT?
    It’s kind of like HTML, it’s called jsx

    My very first React component!

    View full-size slide

  18. BUT, WE NEED TO EXPORT
    the Media component, so it can be used in other files
    module.exports = {
    Media: Media
    };

    View full-size slide

  19. DESCRIBE IT WITH A
    RENDER FUNCTION
    This tells the browser what HTML to render.
    var Media = React.createClass({
    render: function () {
    return (

    {this.props.children}

    );
    }
    });
    just render a paragraph, for now
    tell React where to
    render children

    View full-size slide

  20. 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

    View full-size slide

  21. LET’S TRY IT!
    Sweet, this is gonna be rad.

    This text is our component’s children!

    !
    !
    !
    !

    This text is our component’s children!

    View full-size slide

  22. LET’S TRY IT!
    Sweet, this is gonna be rad.

    This text is our component’s children!

    !
    !
    !
    !

    This text is our component’s children!

    When React renders that
    component we get this html

    View full-size slide

  23. LET’S TRY IT!
    Sweet, this is gonna be rad.

    This text is our component’s children!

    !
    !
    !
    !

    This text is our component’s children!

    {this.props.children}
    When React renders that
    component we get this html

    View full-size slide

  24. NOT VERY USEFUL, RIGHT?
    You'd never use react to render a simple paragraph because it
    already understands tags, you can just use them!

    View full-size slide

  25. LET’S BUILD AN ACTUAL
    MEDIA BLOCK
    Step 1: Add the left image

    View full-size slide

  26. 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

    View full-size slide

  27. 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

    View full-size slide

  28. CREATE A SOURCE
    ATTRIBUTE
    We’ll use it in our render function to set the src of the image

    Media block content

    React props are a
    lot like HTML
    attributes

    View full-size slide

  29. BUT WAIT, THE IMAGE CAN
    BE A LINK
    Sometimes…

    View full-size slide

  30. SO, LET’S ADD AN HREF
    ATTRIBUTE
    leftImageSource='http://placehold.it/50x50'
    leftImageHref='http://www.google.com'>
    Media block content

    Our render function will
    make this into a link
    wrapper (if it is set)

    View full-size slide

  31. THE IMAGE CAN BE
    VERTICALLY ALIGNED

    View full-size slide

  32. ADD AN ALIGNMENT
    ATTRIBUTE
    leftImageSource='http://placehold.it/50x50'
    leftImageHref='http://www.google.com'
    leftImageAlignment='middle'>
    Media block content

    vertical alignment, could be
    top, middle or bottom

    View full-size slide

  33. OH SHOOT, ACCESSIBILITY!

    View full-size slide

  34. WE NEED AN ALT
    ATTRIBUTE
    leftImageSource='http://placehold.it/50x50'
    leftImageHref='http://www.google.com'
    leftImageAlignment='middle'
    leftImageAlt="profile photo">
    Media block content

    Our render function will make
    this into an alt attribute on the
    tag

    View full-size slide

  35. OH, AND PERFORMANCE!

    View full-size slide

  36. WE NEED A HEIGHT AND
    WIDTH
    leftImageSource='http://placehold.it/50x50'
    leftImageHref='http://www.google.com'
    leftImageAlignment='middle'
    leftImageAlt="profile photo"
    leftImageHeight="50px"
    leftImageWidth="50px">
    Media block content

    Explicit height and width
    allow the browser to do a
    single rendering/painting
    pass

    View full-size slide

  37. SET THE GUTTER BETWEEN
    IMAGE AND CONTENT
    with the spacing attribute
    leftImageSource='http://placehold.it/50x50'
    leftImageHref='http://www.google.com'
    leftImageAlignment='middle'
    leftImageAlt="profile photo"
    leftImageHeight="50px"
    leftImageWidth="50px"
    leftImageSpacing="medium">
    Media block content

    For when the 10px default
    spacing isn’t right, like a tiny
    icon with text

    View full-size slide

  38. PROPERTIES OF THE MEDIA
    rather than its images

    View full-size slide

  39. FOR EXAMPLE, IT’S
    RESPONSIVE
    via the stacksize (breakpoint) attribute
    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

    stack size puts the image
    above the text at the
    breakpoint

    View full-size slide

  40. THIS IS GETTING
    OUT OF HAND!
    But we forgot something, the media block can have a right
    image

    View full-size slide

  41. ADD THE RIGHT IMAGE
    PROPERTIES
    This is out of control, we are going the wrong way!
    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

    right image
    props

    View full-size slide

  42. 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?

    View full-size slide

  43. 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

    View full-size slide

  44. 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

    View full-size slide

  45. 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"
    }
    ];

    View full-size slide

  46. JSON IN THE MEDIA
    passed in as another property
    images={images}
    bodyAlignment='middle'
    stackSize='medium'>
    Media block content

    View full-size slide

  47. JSON IN THE MEDIA
    passed in as another property
    images={images}
    bodyAlignment='middle'
    stackSize='medium'>
    Media block content

    {curly braces} mean it’s a JavaScript
    variable rather than a string

    View full-size slide

  48. JSON IN THE MEDIA
    passed in as another property
    images={images}
    bodyAlignment='middle'
    stackSize='medium'>
    Media block content

    json goes into the
    images attribute
    {curly braces} mean it’s a JavaScript
    variable rather than a string

    View full-size slide

  49. 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 tag
    ❖ cleaner separation of
    concerns (media takes care
    of media stuff, rather than
    the properties of its
    children)

    View full-size slide

  50. 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

    View full-size slide

  51. 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

    View full-size slide

  52. PARSING CHILDREN
    better, everything is normal html! But, it has a few drawbacks

    href='http://www.google.com' alignment='middle'
    alt="profile photo" height="50px" width="50px" >
    My media content
    href='http://www.google.com' alignment='middle'
    alt="profile photo" height="50px" width="50px" >

    View full-size slide

  53. 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

    View full-size slide

  54. 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

    View full-size slide

  55. 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

    View full-size slide

  56. REACT BUILT-IN
    COMPONENT
    In react, everything is a component.

    View full-size slide

  57. FIRST, WE MAKE OUR
    IMAGES
    var leftImage = alignment='middle' alt="profile photo"
    height="50px" width="50px">;
    !
    var rightImage = alignment='middle' alt="profile photo"
    height="50px" width=“50px">;

    View full-size slide

  58. NEXT, WE MAKE OUR
    MEDIA OBJECT
    this looks similar to the JSON example
    leftImage={leftImage}
    rightImage={rightImage}
    bodyAlignment='middle'
    stackSize='medium'>
    Media block content

    View full-size slide

  59. NEXT, WE MAKE OUR
    MEDIA OBJECT
    this looks similar to the JSON example
    leftImage={leftImage}
    rightImage={rightImage}
    bodyAlignment='middle'
    stackSize='medium'>
    Media block content

    left and right images are
    passed into attributes

    View full-size slide

  60. YOU CAN EVEN WRITE IT
    like this if you really want to
    leftImage={href='http://www.google.com' alignment='middle'
    alt="profile photo" height="50px" width="50px">}
    bodyAlignment='middle'
    stackSize='medium'>
    Media block content

    image component directly in
    the attribute property

    View full-size slide

  61. 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

    View full-size slide

  62. 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!



    ...
    Yuck!

    View full-size slide

  63. WE CONSIDERED GOING
    BACK TO PROPERTIES…
    but decided we should make our own wrapper

    to property or not to property?

    View full-size slide

  64. 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

    View full-size slide

  65. 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

    View full-size slide

  66. GOAL: OUTPUTS A SIMPLE
    TAG
    but won't pass through attributes

    that don't make sense like href

    View full-size slide

  67. STEP 1: CREATE THE IMAGE
    COMPONENT
    var Image = React.createClass({
    !
    });

    View full-size slide

  68. STEP 2: EXPORT THE IMAGE
    the same way we did the Media component
    module.exports = {Image};

    View full-size slide

  69. STEP 3: GET ITS PROPERTIES
    and render an image
    var Image = React.createClass({
    render() {
    var {href, src, children, className, ...other} = this.props;
    !
    var image = ;
    !
    return href ? {image} : image;
    }
    });

    View full-size slide

  70. STEP 3: GET ITS PROPERTIES
    and render an image
    var Image = React.createClass({
    render() {
    var {href, src, children, className, ...other} = this.props;
    !
    var image = ;
    !
    return href ? {image} : image;
    }
    });
    get the properties we need

    View full-size slide

  71. STEP 3: GET ITS PROPERTIES
    and render an image
    var Image = React.createClass({
    render() {
    var {href, src, children, className, ...other} = this.props;
    !
    var image = ;
    !
    return href ? {image} : image;
    }
    });
    get the properties we need
    build the image from our properties

    View full-size slide

  72. STEP 3: GET ITS PROPERTIES
    and render an image
    var Image = React.createClass({
    render() {
    var {href, src, children, className, ...other} = this.props;
    !
    var image = ;
    !
    return href ? {image} : image;
    }
    });
    get the properties we need
    build the image from our properties
    if we have a link, wrap the image in an tag

    View full-size slide

  73. 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 = ;
    return href ? {image} : image;
    }
    });

    View full-size slide

  74. 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 = ;
    return href ? {image} : image;
    }
    });
    get the responsive property

    View full-size slide

  75. 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 = {children};
    return href ? {image} : image;
    }
    });

    View full-size slide

  76. 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 = {children};
    return href ? {image} : image;
    }
    });
    add this class
    if this evaluates
    to true

    View full-size slide

  77. 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 = {children};
    return href ? {image} : image;
    }
    });
    add this class
    if this evaluates
    to true
    then, put the class
    on the image

    View full-size slide

  78. 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 = {children};
    return href ? {image} : image;
    }
    });

    View full-size slide

  79. 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 = {children};
    return href ? {image} : image;
    }
    });
    responsive has to
    be true or false

    View full-size slide

  80. 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 = {children};
    return href ? {image} : image;
    }
    });

    View full-size slide

  81. 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 = {children};
    return href ? {image} : image;
    }
    });
    the href is a string

    View full-size slide

  82. 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 = {children};
    return href ? {image} : image;
    }
    });

    View full-size slide

  83. 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 = {children};
    return href ? {image} : image;
    }
    });
    src is a string and
    required

    View full-size slide

  84. 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 = {children};
    return href ? {image} : image;
    }
    });

    View full-size slide

  85. 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 = {children};
    return href ? {image} : image;
    }
    });

    View full-size slide

  86. 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!

    View full-size slide

  87. 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

    View full-size slide

  88. 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

    View full-size slide

  89. DESIGNERS ONLY USE 2
    KINDS OF ALIGNMENT
    ❖ Traditional media with everything top aligned

    !
    !
    !
    ❖ “Flag” component a la Harry Roberts middle aligns

    View full-size slide

  90. 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 component

    refresh

    View full-size slide

  91. 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

    View full-size slide

  92. ARE ANY OF THESE
    WRONG?
    No, absolutely not.
    https://gist.github.com/stubbornella/e97662e4a197eb9a534a

    View full-size slide

  93. 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

    View full-size slide

  94. 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'
    }
    ]

    View full-size slide

  95. TABS IN BOOTSTRAP

    !



    Home



    Profile


    !


    ...
    ...

    !

    View full-size slide

  96. TABS IN REACT


    ...


    ...


    View full-size slide

  97. 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

    View full-size slide

  98. KEEP LOOPING BACK
    change the interface until it works well

    View full-size slide

  99. 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

    View full-size slide

  100. 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-

    View full-size slide

  101. USE ALL THE TOOLS IN
    YOUR TOOLBOX
    ❖ Elements (built in and custom)

    ❖ Attributes (simple and objects)

    ❖ JSON

    ❖ Children

    View full-size slide

  102. styleguide.pivotal.io

    View full-size slide

  103. WE OPEN SOURCED
    EVERYTHING
    Please do give us feedback

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

    github: github.com/pivotal-cf/pivotal-ui

    View full-size slide

  104. THANK YOU!
    @stubbornella

    View full-size slide