Show HN: Styled-components – Use the best of ES6 to style React apps
styled-components.com
styled-components.com
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/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> 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.
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.Other than that: try it out ;)
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.
"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.
[0] https://developer.mozilla.org/en-US/docs/Web/JavaScript/Refe...
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.
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 :)
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.
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...
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`...
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...
(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}])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.
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)
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.
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.
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.
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
By usual way I mean using inline styles the React way i.e. style={_componentStyle}
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?
const FocusInput = styled.input`
&:focus {
focus-styles: here;
}
`;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
[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...
Note: You can also use this in real projects ;)
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)
Glad you liked it :)
const AdjustsAt360px = styled.div`
@media screen and (max-width: 360px) {
this-is-applied-under: 360px;
}
`;(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"?)
See https://github.com/FormidableLabs/radium#how-does-radium-wor...
(that's the difference between _inline styles_ (<p style={styles} />) and CSS-in-JS (<p className={styles} />) libs)
https://github.com/MicheleBertoli/css-in-js
Or this influential talk:
Looking forward to giving this a shot on my next side project.
(Feel free to dig into the code and submit a PR if you're so inclined! https://github.com/styled-components/styled-components.githu...)