
Show HN: Styled-components – Use the best of ES6 to style React apps - mxstbr
https://styled-components.com
======
cel1ne
I want to mention my styling library here:
[https://www.npmjs.com/package/react-native-style-
tachyons](https://www.npmjs.com/package/react-native-style-tachyons)

The best part: it gives you a consistent spacing [0] and a consistent font
scale [1] which is relative to rem. No more magic values, just use classes:

    
    
        ma0 ... ma7            margin: 0|0.25|0.5|1|2|4|8|16 rem
        ml|mr|mb|mt [0-7]      marginLeft, marginRight, marginBottom, marginTop
        mh [0-7]               marginHorizontal
        mv [0-7]               marginVertical
    
        /* Same with p for padding */
    

No more stylesheets, everything is there at a glance and easily fixable:

    
    
        <View cls="bt bb jcfs pa2">           /* border at top and bottom, justifyContent: stretch, padding: 0.5rem */
           <Text cls="white tc">           /* white color, text-align: center */
               Something
           </Text>
        </View>
    
    

[0]
[http://tachyons.io/docs/layout/spacing/](http://tachyons.io/docs/layout/spacing/)

[1]
[http://tachyons.io/docs/typography/scale/](http://tachyons.io/docs/typography/scale/)

~~~
mxstbr
That's awesome, I love tachyons!

styled-components is on a slightly "lower" level in a certain sense, you would
build components like yours with styled-components:

    
    
        const TachyonsText = styled.Text`
          ${props => props.bt ? 'some: styles;' : 'other: styles;'}
        `;
    

Those functions could then be extracted and reused across your components:

    
    
        const bt = (props) => props.bt ? 'some: styles;' : 'other: styles;';
    
        const TachyonsText = styled.Text`
          ${bt} ${bb} ${jcfs}
        `;
    

And then you can use your component like any other tachyons component:

    
    
        <TachyonsText bt bb>Text here</TachyonsText>

~~~
mxstbr
To elaborate on this just a tiny bit, you can use tachyons-js[0] by the
amazing jongold to automate even more of this:

    
    
        import tachyons from 'tachyons-js';
    
        const tachyonsHelperFunc(props) => Object.keys(props).map(prop => tachyons[prop])
    
        const MyTachyonsComp = styled.div`${tachyonsHelperFunc}`;
    

This way, MyTachyonsComp can now has all the benefits of styled-components
(easy theming and overriding, power of JS for styling, ReactNative, nesting,…)
while also being able to use tachyons really easily:

    
    
        <MyTachyonsComp ma2 ph2 bb />
    

In fact, you could probably even wrap the above helper to make it really easy
to use:

    
    
        const styledTachyonsComponent = (...args) = styled(..args)`${tachyonsHelperFunction}`;
    

Now you can created styled-tachyons-components really easily:

    
    
        const MyTachyonsStyledDiv = styledTachyonsComponent('div');
    

:tada:

Note: I just coded this in this comment, might be some typos in there.

[0]: [https://github.com/jongold/tachyons-
js](https://github.com/jongold/tachyons-js)

------
nmalaguti
For anyone unfamiliar with the syntax used to achieve this, it's called Tagged
Template Literals [0] and it's part of ES2015. You have a function that
receives the static strings and interpolations and can return anything you
want.

[0] [https://developer.mozilla.org/en-
US/docs/Web/JavaScript/Refe...](https://developer.mozilla.org/en-
US/docs/Web/JavaScript/Reference/Template_literals)

~~~
AgentME
One of my favorite uses of tagged template literals is for HTML-encoding
variables into an HTML string with (my module)
[https://www.npmjs.com/package/auto-html](https://www.npmjs.com/package/auto-
html).

------
andreypopp
I think using strings as an API is a step in the wrong direction. I like that
it produces a React component directly though.

We experimented with styling approaches for React a while ago and produced our
solution — React Stylesheet[1], which we used for over an year in different
React applications.

It also produces components out of style definitions directly:

    
    
        let GreenBox = style('div', {
          base: {
            background: 'green'
          }
        })
    

Which you can use like any other React component later:

    
    
        <GreenBox />
    

As you can see the API is kinda similar but uses JS instead of CSS string.
What are advantages? The following:

* Consistent syntax: you can use functions, variabls, mixins, w/o the need for interpolation `${...}`.

* Tooling. This is big one. You can make your stylesheets linted with ESLint and typesafe (!!!) with FlowType or TypeScript.

FlowType is supported out of the box, see [2]. Typesafe stylesheets is a huge
win for productivity, I constantly catch typos and invalid values via Flow.

[1]: [https://github.com/prometheusresearch/react-
stylesheet/blob/...](https://github.com/prometheusresearch/react-
stylesheet/blob/next/README.md) [2]:
[https://github.com/prometheusresearch/react-
stylesheet/blob/...](https://github.com/prometheusresearch/react-
stylesheet/blob/next/README.md#type-safety)

EDIT: additions

Styles are compiled into CSS so :hover and friends work here.

~~~
mxstbr
Hey Andrey! :wave:

If you reading this are interested in a discussion about this, read this tweet
by Andrey and the following replies:
[https://twitter.com/andreypopp/status/786524437843615744](https://twitter.com/andreypopp/status/786524437843615744)
:)

------
drinchev
What is the performance penalty of using generated styles on every render?

As far as I can see from the source code, React will have to modify `<style>`
tag every time a component is being rendered.

I still think the best way to handle stylesheets is with external css file (
doesn't matter how it's generated. I use CSSModules ) and then add static
class names for those components.

~~~
mxstbr
We've tried styled-components in medium-size projects (50-500 components) and
haven't noticed any performance-hit yet. That being said, it's definitely
something we're conscious about.

That's why we will be writing a babel transform that grabs all the _static_
styles and extracts them into a separate stylesheet! (just didn't have time to
do it until ReactNL where I just announced it)

See this issue for more information, and if anybody reading this has
experience with babel transforms please holla since we can definitely use your
help! [https://github.com/styled-components/styled-
components/issue...](https://github.com/styled-components/styled-
components/issues/59)

~~~
onetom
You mean extract into a separate stylesheet file?

Wouldn't that lead to
[https://en.wikipedia.org/wiki/Flash_of_unstyled_content](https://en.wikipedia.org/wiki/Flash_of_unstyled_content)
issues?

Maybe some memoization could help if there are performance issues with
regenerating `document.styleSheets`...

------
pgt
After Reagent + Hiccup, I'm ruined. Nothing feels as natural as a full,
general-purpose language (Clojure) combined with a natural keyword-based DSL
for styling:

    
    
      (defn right-cell [& body]
        [:td.right.aligned body])  ;; renders <td class="right aligned>{...body}</td>
    
      (defn person-row [{:keys [name age] :as p}]
        [:tr
          [:td name]
          [right-cell age]])
    
      (defn person-table [font-size people]
        (let [heading-size (* font-size 1.6)]
          [:div
            [:h1 {:style {:font-size (str heading-size "em")}
              "People List"]
            [:table.ui.basic.table
              [:tbody (map person-row people)]]]))
    
      (defn main []
        [person-table 2 [{:name "John" :age 21} {:name "Sally" :age 22}])

------
z3t4
With components I think we are taking a step back from semantic HTML elements,
where style is applied by a separate template. And business logic is also
separated from the layout elements.

~~~
danneu
The cutting edge of front-end development has been arriving at ways to split
business logic from layout elements for some time now.

Redux, Om, Reframe, Elm, etc. They all amount to hooking up components to a
state transactor where the business logic lives separately.

Semantic HTML seems like a trade-off where you clean your markup at the
expense of indirection, not a universal aspiration. And components don't
dictate where your styling should live.

~~~
z3t4
In classic HTML you use id attributes for the JavaScript, and class attributes
for the style-sheet.

~~~
King-Aaron
I agree, I still don't see the benefit here.

------
ioseph
I'm probably missing something but what's the advantage of this over usual way
of defining styles in React?

~~~
mxstbr
What do you mean with "the usual way"? ;)

There is vanilla CSS, Sass, CSS modules, Aphrodite, Radium, JSS,…

This image from the talk I just gave about it sums the differences up quite
well: [http://imgur.com/dmiROz6.jpg](http://imgur.com/dmiROz6.jpg)

You can also see a comparison with other styling methods here:
[https://github.com/styled-components/comparison](https://github.com/styled-
components/comparison) (this is where the checklists are from)

~~~
madeofpalk
Interesting. What warrants a for CSS Modules co-location? Is it just because
you can't write it in the same JS file as your component?

I'm also super duper skeptical of style interoperability between React Native
and the browser. From experience styling in React Native suffers from the
uncanny valley - its so close to browser CSS, but ends up failing in rather
significant ways (mainly layout) that would prevent style reuse.

~~~
mxstbr
Yes exactly.

It's less about interoperability and more about using the same styling system
for_all_ parts of your application. Styling on ReactNative is different enough
to have to be careful when doing it, though theoretically it's very possible.

------
elecengin
How do you do pseudo classes like :focus?

~~~
mxstbr
Like this:

    
    
        const FocusInput = styled.input`
          &:focus {
            focus-styles: here;
          }
        `;

------
jeswin
glamor is another option for React apps, if inline styling is your thing.
[https://github.com/threepointone/glamor](https://github.com/threepointone/glamor)

~~~
mxstbr
glamor is amazing, Sunil really outdid himself with it. In fact, his injection
mechanism is so good we blatantly copied it for styled-components!

On the other side, Sunil is looking into stealing some of the general ideas
from styled-components which I'm really looking forward to:
[https://github.com/threepointone/glamor/issues/70](https://github.com/threepointone/glamor/issues/70)

------
cfv
Neat. Now, why not actual CSS?

~~~
mxstbr
Can I forward you to these four resources? (I realize this might sound like a
cop-out answer, but these people have summed up the benefits of CSS-in-JS so
much better than I could in two minutes!)

[0]: Rendering Khan Academy’s Learn Menu Wherever I Please: Documenting the
move from the handlebars + less combo to react and css-in-js, and why
KhanAcademy did it

[1]: My thoughts on Inline Styles: A great collection of both pros and cons
about styles in javascript. Most of those doubts we've tried to solve with
styled-components

[2]: "Scale" FUD and Style Components: Using components as low-level styling
constructs

[3]: Ryan's random thoughts about inline styles: Explaining some benefits of
using styles in js

BONUS

[4] The Future of Reusable CSS: How component libraries should be styled, and
why they're not yet

\----

[0]: [https://medium.com/@jdan/rendering-khan-academys-learn-
menu-...](https://medium.com/@jdan/rendering-khan-academys-learn-menu-
wherever-i-please-4b58d4a9432d#.w9nshye05)

[1]: [https://medium.com/@andrewingram/my-thoughts-on-inline-
style...](https://medium.com/@andrewingram/my-thoughts-on-inline-styles-
da94682b5e35#.trbnpmcn9)

[2]: [https://medium.com/learnreact/scale-fud-and-style-
components...](https://medium.com/learnreact/scale-fud-and-style-
components-c0ce87ec9772#.kzjba8lcg)

[3]:
[https://www.youtube.com/watch?v=EkPcGS4TzdQ](https://www.youtube.com/watch?v=EkPcGS4TzdQ)

[4]:
[https://www.youtube.com/watch?v=XR6eM_5pAb0](https://www.youtube.com/watch?v=XR6eM_5pAb0)

~~~
cfvergara
Neat. Thanks!

------
anilgulecha
What's the font in the code-editor screenshot? The italics look good!

~~~
mxstbr
It's Operator Mono by Hoefler & Co!
[http://www.typography.com/fonts/operator/overview/](http://www.typography.com/fonts/operator/overview/)

~~~
pcr0
Hooking onto this, what's the colorscheme?

~~~
mxstbr
Syntax Theme: Base16 Ocean Dark Spacegray! (and UI Theme: One Dark)

------
andrewvijay
Great one! Would love to do this in my side projects.

~~~
mxstbr
Let us know how it goes, we'd love to know what you think!

Note: You can also use this in real projects ;)

~~~
andrewvijay
Real projects in the future may be! Because the current one involves a lot of
components and I don't think this would be scaling well as it's gonna rerender
the styles multiple times.

~~~
mxstbr
Sorry, how do you mean "rerender the styles multiple times"? The only time any
styles ever change is if one of your interpolations changes, but otherwise we
don't do much calculation at all!

That being said, there might be a performance impact in massive (1000+
components) applications. We've tried it in medium apps, and haven't seen any
performance impact yet. We're also going to build a babel transform to extract
the static styles to get even better performance. (see
[https://news.ycombinator.com/item?id=12700280](https://news.ycombinator.com/item?id=12700280))

~~~
andrewvijay
Hmm yup I mistyped that. I was a bit worried about the performance because the
app is a multi tab grafana like dashboard with real time data. I'll try by
modifying components that dont change often. Will measure and go up from
there.

------
himlion
Saw your talk this morning at reactnl, cool stuff!

~~~
mxstbr
Hah, small world! (if you want to call HN small)

Glad you liked it :)

------
Kiro
What about media queries?

~~~
mxstbr
Just like any other media query, except without the selector!

    
    
        const AdjustsAt360px = styled.div`
          @media screen and (max-width: 360px) {
            this-is-applied-under: 360px;
          }
        `;

~~~
hkeide
How is this implemented? And how is the :hover pseudo class implemented?
Awesome work by the way!

~~~
mxstbr
It isn't "implemented" – it's just CSS! Literally!

(Note: Almost the sole thing we do to that CSS before injecting it into the
DOM is adding a hash of the contents as the selector. Not sure if that counts
as "implemented"?)

~~~
hkeide
Thank you, that's what I wanted to know, since projects like Radium implement
e.g. hover in JS using onMouseEnter() etc, which sounds slow.

See [https://github.com/FormidableLabs/radium#how-does-radium-
wor...](https://github.com/FormidableLabs/radium#how-does-radium-work)

~~~
mxstbr
Exactly, they use inline styles, we use CSS. :)

(that's the difference between _inline styles_ (<p style={styles} />) and CSS-
in-JS (<p className={styles} />) libs)

~~~
hkeide
I don't think everyone uses that distinction, see this list for example.
Radium is included among others:

[https://github.com/MicheleBertoli/css-in-
js](https://github.com/MicheleBertoli/css-in-js)

Or this influential talk:

[https://speakerdeck.com/vjeux/react-css-in-
js](https://speakerdeck.com/vjeux/react-css-in-js)

~~~
mxstbr
I very much realize that, which is why I've been pushing towards people
recognizing this because it _does_ make a huge difference! (as seen by the OC
that kicked off this discussion)

------
Raphmedia
Emoji as CSS classes. Never thought of that one...

------
gjolund
Very cool, I have been playing around with this idea for a little bit now and
your implementation looks solid.

Looking forward to giving this a shot on my next side project.

------
retox
Site is a blank page for me.

~~~
mxstbr
Which browser/OS?

(Feel free to dig into the code and submit a PR if you're so inclined!
[https://github.com/styled-components/styled-
components.githu...](https://github.com/styled-components/styled-
components.github.io))

~~~
retox
Apologies, didn't see your reply until now. IE11 behind the company firewall,
I can see a rather short set of complete HTML in the source but nothing is
rendered. Sorry I can't offer more information.

