Hacker News new | past | comments | ask | show | jobs | submit login
Show HN: Styled-components – Use the best of ES6 to style React apps (styled-components.com)
172 points by mxstbr on Oct 13, 2016 | hide | past | favorite | 67 comments



I want to mention my styling library here: 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/

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


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>


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


Another option for creating a customizable, consistent font scale and spacing is my Typography.js project http://kyleamathews.github.io/typography.js/

It's a JS library that you provide a configuration object and it generates your type/spacing CSS. I love Tachyons and am planning on building a plugin for Typography.js which will generate tachyon-like classes.

https://github.com/kyleamathews/typography.js


You can use it with css-in-js libs like styled-components as well. It exports two helper functions, "rhythm" and "scale".

"rhythm" is a virtual unit that's the distance of one line-height. All spacing within Typography.js are based on it. Using "rhythms" for other spacings on your site ensures everything stays consistent as you make styling tweaks.

"scale" is a function to pick font sizes off the scale you setup (with scaleRatio). This let's you tweak the body font size and all other font sizes will move along with that.


For those critical applications where typing out inline styles is just too many characters, I guess.


Tachyons' main-purpose is not abbreviating inline-styles, but providing the developer with a consistent and scalable layouting-system for spacing and typography, which, at the end, is what arrives at the user.

If you love your inline-styles you can keep them and use tachyons just for the scale:

    import { sizes } from "react-native-style-tachyons

    <MyComp
        style={{
            fontSize: sizes.f2,
            height: sizes.h1,
            paddingTop: sizes.pt1,
            backgroundColor: "#232323"
        }}
    />
Though I still think

    <MyComp cls="f2 h1 pt1 bg-#232323" />    /* string is checked for validity of course */
is much cleaner.


Tachyons is the library that made me like designing web pages again.


What's so good about it?


Here's a longer article on how tachyons came to be: http://mrmrs.io/writing/2016/03/24/scalable-css/

Other than that: try it out ;)


Does the package "react-native-style-tachyons" also work for non-React-Native projects?


For HTML-DOM you can use the regular tachyons package: https://www.npmjs.com/package/tachyons


Thanks, I'll give it a try


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


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.


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/... [2]: https://github.com/prometheusresearch/react-stylesheet/blob/...

EDIT: additions

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


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 :)


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.


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


You mean extract into a separate stylesheet file?

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

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


Within React there are two approaches:

1. It uses the `style` prop, which modifies the CSSStyleDeclaration object on the DOM node. The style attribute gets set by the browser behind the scenes. [1]

2. The rendering happens on the server, and React produces the markup for the style attribute. [2]

The former approach has very little overhead. The second bears the overhead of having to be parsed.

In most libraries, this is what gets used. Some libraries try to be clever, though, and inject `<style>` or `<link>` elements into the DOM (mostly to support things like `:hover`). This can get extremely CPU intensive, though, and it's not uncommon to get burned by a library in this way.

[1] https://github.com/facebook/react/blob/c78464f8ea9a5b00ec802...

[2] https://github.com/facebook/react/blob/c78464f8ea9a5b00ec802...


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}])


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.


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.


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


I agree, I still don't see the benefit here.


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


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

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


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.


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.


Note that while CSS modules doesn't provide an out-of-the-box solution for themeing you can use css variables and then either just swap out the variables (if you only target browsers that support the custom properties spec) or run the CSS through postCSS.

The important difference however is that CSS-in-JS can swap out themes on the fly whereas this would be a static solution that doesn't scale e.g. if you need per-user customization.


> if you only target browsers that support the custom properties spec

That "sidenote" is exactly why vanilla CSS has a "Kinda" for theming. Taking a look at caniuse[0], only 66.39% of browsers have support for custom properties – not exactly production ready.

That being said, once custom properties are well supported they're an amazing solution for theming! Take a look at this talk Glen (the co-creator of CSS modules and now styled-components) gave at JSConf BP for some hints towards this future: https://www.youtube.com/watch?v=XR6eM_5pAb0

[0]: http://caniuse.com/#feat=css-variables


IMO PostCSS is a workable solution until that number gets closer to 100%. It just requires the aforementioned post-processing step per theme to "render" the stylesheet with the correct variables:

https://github.com/postcss/postcss-custom-properties


Sorry just realised my question wasn't clear at all

By usual way I mean using inline styles the React way i.e. style={_componentStyle}


The huge downside with inline styles is that they don't support all of CSS _at all_. You have to reimplement basic things like pseudo selectors (hover/active/focussed/… styles) and things like pseudo elements, media queries, keyframes are non-existant. On top of that, for the eventual global style you need (e.g. @font-face) you now have to add a separate build step for actual CSS to add that.

We have a language on the web that's made for styling. It has support for all those things by default. It's called CSS. Why not use it?


How do you do pseudo classes like :focus?


Like this:

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


glamor is another option for React apps, if inline styling is your thing. https://github.com/threepointone/glamor


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


Neat. Now, why not actual CSS?


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

[1]: https://medium.com/@andrewingram/my-thoughts-on-inline-style...

[2]: https://medium.com/learnreact/scale-fud-and-style-components...

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

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


Neat. Thanks!


Am I an outlier for enjoying plain CSS? I get everything I need and want with css-modules, classnames/bind, and the occasional inline style.


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


It's Operator Mono by Hoefler & Co! http://www.typography.com/fonts/operator/overview/


Hooking onto this, what's the colorscheme?


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


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


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

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


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.


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)


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.


Saw your talk this morning at reactnl, cool stuff!


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

Glad you liked it :)


What about media queries?


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;
      }
    `;


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


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"?)


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


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)


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

Or this influential talk:

https://speakerdeck.com/vjeux/react-css-in-js


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)


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


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.


Site is a blank page for me.


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


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.




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: