Glamorous v4 is here 💄 🎉 🎊

glamorous v4 has been released with a bunch of new features and performance enhancements (glamorous v4 release notes), jest-glamor-react v3 has been released (jest-glamor-react v3 release notes), glamorous-primitives has been released, and the official glamorous website has been released: https://glamorous.rocks (try out the getting started page)!

Status update

It’s been about 4 months since glamorous was officially released. In that time, glamorous has received incredible adoption. And the trajectory is looking really great. We just surpassed 2k stars 🌟 on GitHub (have you starred it yet?). When comparing the similar solutions glamorous is soon to be the number 2 most downloaded solution. While download stats are not a super indicator of the success of open source libraries, I am excited by the implication that glamorous is at least useful enough for multiple people to download it more than once 🙃.

More important than the download numbers are the number of contributors to the project. We have received contributions from many people. There have been over 50 code contributors on the core GitHub project and 32 code contributors on the official website repo. There are even more people who have reported bugs, reviewed pull requests, and helped support users on the chat.

Glamorous is a beginner-friendly open source project with a inclusive code of conduct and helpful community (special shoutout to Luke John and Paul Molluzzo). A welcoming and inclusive open source programming community are important to me, and I hope glamorous continues down this path.

What’s new in glamorous v4?

The new glamorous.rocks website!!

The glamorous community has been hard at work on https://glamorous.rocks, the new documentation website. It’s complete with full API documentation, examples from the community, and a great getting started guide. There’s been a strong effort to localize the website and make it accessible. It’s currently available in 5 languages (English, Español, Français, Deutsch, and 中文) and we’d love contributions to make it available in more! I feel that having the documentation in many languages is critical to helping as many people as possible learn to use and contribute to the project.

withProps

Sometimes it can be useful to apply props by default for a component. The simplest way to do this is by simply setting the defaultProps value on the glamorousComponent. But if you want a little more power and composition, then the withProps APIs can help.

These APIs are highly composable, it would be hard to show you all the examples of how this composes together. Just know that it behaves as you might expect.

// when creating a glamorousComponentFactory
const bigDivFactory = glamorous('div', {withProps: {big: true}})
const BigDiv = bigDivFactory(({big}) => ({fontSize: big ? 20 : 10}))
render(<BigDiv />) // renders with fontSize: 20
render(<BigDiv big={false} />) // renders with fontSize: 10
// applying props to an existing component
const MyDiv = glamorous.div(({small}) => ({fontSize: small ? 10 : 20}))
const SmallDiv = MyDiv.withProps({small: true})
render(<SmallDiv />) // renders with fontSize: 10

Based on these examples, there are three places you can apply props to a glamorous component. How these props are composed together applies in this order (where later has more precedence):

1. Creating a glamorousComponentFactory
2. Directly on a glamorousComponent with the .withProps function
3. When rendering a component (just like applying props to a regular components)

In addition to this, you can also have dynamic props. And these props don’t have to be used for glamorous styling, any valid props will be forwarded to the element:

const BoldDiv = glamorous
.div(({bold}) => ({fontWeight: bold ? 'bold' : 'normal'}))
.withProps(({bold}) => ({
className: bold ? 'bold-element' : 'normal-element'
}))
render(<BoldDiv />) // renders <div class="bold-element" /> with fontWeight: bold
render(<BoldDiv bold={false} />) // renders <div class="normal-element" /> with fontWeight: normal

One cool aspect to this is it allows you to map props to other props as well:

const FormInput = glamorous
.input({/* styles */})
.withProps((props) => ({
pattern: props.creditCard ? creditCardPattern : null,
}))

There’s more to this API, so give it a try. I’m sure you’ll find it really powerful.

propsAreCssOverrides

One API that many people have loved from glamorous is the ability to render components that are styled without giving those things names like “Wrapper” or “Container” (inspired by jsx-style). These components accept props as css values like so:

render(<glamorous.Div marginTop={20} />)
// renders <div /> with margin-top: 20px;

However, this only worked with built-in components. With glamorous v4, you can now get this same behavior for your own components as well:

const MyDiv = glamorous('div', {propsAreCssOverrides})({marginTop: 20})
render(<MyDiv marginTop={10} />)
// renders <div /> with margin-top: 10px;

You can also compose these kinds of components as well:

const MyArticle = glamorous(glamorous.Article)({marginBottom: 10})
render(<MyArticle paddingLeft={20} />)
// renders <article /> with margin-bottom: 10px; padding-left: 20px;

I hope that this allows more expressive APIs in the future.

shouldClassNameUpdate

Most of the time, glamor (the library glamorous uses to generate css) is super fast, but scenarios where the styles are not dynamic it may be nice to prevent glamor from computing your styles on each render (and rerender). In these cases, you can implement shouldClassNameUpdate and if the component is rerendered the class name is not recalculated by glamor. Instead the same class name is reused.

const pureDivFactory = glamorous('div', {
shouldClassNameUpdate(props, previousProps, context, previousContext) {
// return `true` to update the classname and
// `false` to skip updating the class name
return true
},
})
const Div = pureDivFactory({marginLeft: 1})
render(<Div css={{marginLeft: 2}} />)
// this will render:
// <div />
// with {marginLeft: 2}

Note that this is not the same as shouldComponentUpdate and your component will still be rerendered at the appropriate times. shouldClassNameUpdate simply provides a means to opt-out of re-generating the class name unnecessarily.

Readable Class Names

With the release of v2.20.32, glamor introduced the ability to create readable class names for components by defining a label in the style object. The result is a generated class name with the pattern css-[label]-[hash].

// App
const MyRedText = glamorous.div({
label: 'labelForRedText’,
color: 'red’,
})
function App() {
return (
<MyRedText>Whoa!</MyRedText>
)
}
render(<App />, document.getElementById('root'))
// result
<div tabindex="0" class="css-labelforredtext-1cz491u">Whoa!</div>

And if you use babel-plugin-glamorous-displayname, the label will be set automatically! How cool is that!?

Performance Optimizations

Kye Hohenberger found a great optimization by deferring styles resolution and merging to glamor. Benchmarks are silly so it’s hard to tell how this will impact your app. It really depends on how you use glamorous. I hardly noticed a difference in my app, but Kye noticed a ~25% speed increase in mounting of his main App component!

As always, if performance is a real concern of yours, you might also consider glamorous-tiny.

glamorous-primitives

glamorous-primitives is an independent library from Nitin Tulswani that combines glamorous with react-primitives to provide a means of writing components that are usable across multiple target platforms.

glamorous-primitives loaded in Sketch, native iOS, and the browser

Here’s the code from that example:

import React from 'react'
import 'react-primitives'
import glamorous from 'glamorous-primitives'
const StyledView = glamorous.view({
display: 'flex',
justifyContent: 'center',
alignItems: 'center',
})
const StyledText = glamorous.text({
fontSize: 25,
marginTop: 80,
color: 'pink'
})
export default class App extends React.Component {
render () {
return (
<StyledView>
<StyledText>💄 glamorous-primitives 💄</StyledText>
</StyledView>
)
}
}

glamorous-primitives just hit a stable release and this is only the beginning. We’re really looking forward to what glamorous-primitives has to offer the react ecosystem! Shoutout to Nitin Tulswani for this incredible project! This is just one of the related projects the glamorous community has built.

glamorous-native

glamorous-native is a port of glamorous that specifically targets React Native, exporting the same core functionality as glamorous as well as built-in component factories for all React Native elements. It was built and is maintained by the good folks at Robin (specifically Atticus White). For every React Native element, there is an associated glamorous component factory attached to the glamorous function. You can access these factories like so: glamorous.view, glamorous.text, glamorous.listView, etc.

const MyStyledView = glamorous.view({margin: 1})
<MyStyledView>{content}</MyStyledView>
// rendered output: <View style={{margin: 1}}>{content}</View>
// styles applied: {margin: 1}
// style is also cached and registered with `StyleSheet`

This project is actively maintained and has several examples to learn from if you’re interested in trying glamorous-native or new to native development with React Native entirely.

TypeScript updates

In addition to support for all the new features and breaking changes announced, there has been significant improvements to the coverage of existing typing. With a few exceptions (see the release notes) glamorous should now be fully typed!

Oh my! CSS in JS Autocomplete 😱

Huge thank you to Luke John and others for all the work they’ve put into this!

Flow type definitions are coming soon!

jest-glamor-react

One thing we loved about JSX is it made it even easier for us to test UI because our HTML is right there with our JS. With CSS-in-JS, we can do that with CSS too. This is one of the coolest aspects of CSS-in-JS in my eyes. jest-glamor-react allows you to take snapshots of react components and include the CSS that would be rendered with them. It makes finding CSS regressions reasonably possible! And the latest release makes it even better:

Jest snapshot showing CSS-only changes in our output

Shoutout to @jhurley23 for implementing the class name placeholder making reviewing snapshot changes even easier than before!

SWAG! Stickers and T-Shirts

You can purchase glamorous stickers from UnixStickers.com to decorate your laptop, desk, bedroom, and the back of your friends! It comes in two versions: Hex and square. Shoutout to Connor Elsea and Mark Dalgleish for inspiring the logo! Looks super awesome on a sticker, trust me!

There are also two shirts available on Amazon from GSM Studio. They each come in multiple colors as well! And GSM Studio makes a donation of $1 for every shirt purchased to Girls Who Code 🎉 (glamorous Shirt without the name, glamorous shirt with the name)

glamorous SWAG

Breaking Changes

Theme arg removed

When we added theming, we decided the way to do it was to add another parameter to the dynamic styles function arguments:

const MyDynamicallyStyledSpan = glamorous
.span((props, theme) => ({
fontSize: 20,
color: theme.colors.primary
}))

When we added context support, we added it as a third argument. I was disappointed that the dynamic functions resembled React function component arguments, but not quite.

Later we realized that often you don’t need the props argument at all and you’re just trying to get to the theme argument. It’s annoying to have to include the props argument in that case, so we added theme to props. That worked great, so I realized we didn’t need the theme argument anymore. So that’s now been removed!

const MyDynamicallyStyledSpan = glamorous
.span(({theme}) => ({
fontSize: 20,
color: theme.colors.primary
}))

To make this migration as easy as possible, we’ve written a codemod to automatically update your code. It’s already been used by the glamorous website and others to great effect! Try out the codemod!

Config

I’ve never been a big fan of config for libraries, but we added this config for useDisplayNameInClassName for debugging purposes. As we now have readable class names, we don’t need this anymore and we can remove it! There’s no codemod for this because it should be easier just to do it yourself. Just remove any instance of glamorous.config that you have in your codebase (should only appear once anyway).

Conclusion

We’re not done making glamorous even better (and Sunil Pai isn’t done making glamor better either, 🤗🍰). Come help us make it better! We’d especially appreciate help on the website and documentation to make it more complete and accessible to more of the world. Together we can make it easier than ever to build React applications with maintainable CSS.

See you on twitter! @glamorousCSS

Please share this with your friends and family. You can share it via Medium’s 💚, tweet it yourself, and/or simply retweet this:

P.S. Does your company use glamorous? Please let us know! Eventually we’ll add a Users page to the website and we’d love to have users to put on there.

P.S.P.S. PayPal has recently open sourced downshift: 🏎 Primitives to build simple, flexible, WAI-ARIA compliant React autocomplete/dropdown/select/combobox components. Give it a look! I think you’ll love it!

P.S.P.S.P.S. (I keep on thinking of more things to add). If you’re still unconvinced of the whole css-in-js thing (or your co-workers aren’t), then you may find this helpful: