src/.../styled.js - stairway to Styled-Component's CSS-in-JS heaven
March 24, 2019
Using a fabulous open source library like Styled-Components often comes with the nice effect of appreciating what you can do with it more and more and more. If you are like me, at some point you get curious about what happens behind the (library-)scenes. I recently checked the Styled-Components Github repository to know better what’s going on when using the library. As you can imagine the library does A LOT of cool things, so in the first attempt I limited my investigations to the library’s practical entry point.
Remember, creating a styled component with the Styled-Components library is as simple as a that…
const Button = styled.a` font-size: 14px; `;
…or as that
const BorderedButton = styled(Button)` border: 2px solid white; `;
Please pay special attention to the differences of how the
styled function is used in the examples above.
- we call
aas a method of the
styledobject passing it css as an argument
- we call the
styledfunction passing it the previously created styled component as an argument and add css as a next argument
So how does the library provide that exposed possibilities for us? Let’s take a look.
A CSS-in-JS holy grail named styled
Theoretically and taking into account Styled-Component’s
package.json information, the technical runtime entry point to the library is the src/index.js file. But that said, the practical entry point enabling us to do all the cool things is the styled.js file being part of the
/src/constructors directory. Next see what this file looks like (status 01/2019, branch master):
In a nutshell this file does the following:
- some internal imports (lines 2-4)
const styleddeclaration referencing a function (line 8)
- one forEach loop (lines 11-13)
- finally the export of our holy grail
styled🎉 (line 15)
The styled function and its function object methods
styled.js makes heavy use of this. Line 8 shows a
const styled declaration referencing a function, but more on that later. For now just keep in mind that a function referenced by the
styled const was created. Now take a special look at the lines 11 to 13.
We see a forEach loop iterating an array of defined domElements. Each iteration attaches a method with the name of the iterated dom element to the
styled function object. And voilá! There it is, the first hard-working component factory attaching dom element methods to the
styled function object like a boss. The body of each attached method is nothing else than the result of a
styled function call returning a properly built component constructor for each dom node. Having reached this point at runtime we can already call such an attached method like this in our own codebase:
const Button = styled.a` ...this will be the method argument in the form of css to the styled.a call... `; const Container = styled.div` ...this will be the method argument in the form of css to the styled.div call... `;
So far we know (some kind of) what’s going on when we use
styled.div in our codebases using Styled-Components. That said we’ve gone “half the way” to demystify what styled.js exports for us. Remember when I wrote “Line 8 shows a
const styled declaration referencing a function, but more on that later.”? It is that function we need to talk about more right now to demystify the other half. Here we go.
The styled function: how it’s constructed and distributed
Constructed and distributed? Yes!
As you can see in line 8,
styled itself is declared as a function. It is either called directly by us developers using the distributed default export of the
styled function or by calling the function object method which requires internal construction as described above. So in concrete this means for us:
const Container = styled('div')` ...css... `;
const Container = styled.div` ...css... `
returnes exactly the same. But remember: we can conveniently use the second option in our codebase, as Styled-Components takes care of building the proper component constructor executing first option internally to add the function object method (here:
styled function takes a
tag as a parameter and returns the result of calling the function
constructWithOptions (line 8) which receives two arguments.
StyledComponentfunction - Have you noticed I never mentioned
Reactin this post so far? Well, here we go. Let’s not forget Styled-Components is part of the
Reactecosystem. As a result this
StyledComponentargument is used to actually create a React component giving access to React EventHandlers and all the other cool things React does for us.
tagwe’ve passed to the
styledfunction - The argument is of type
Targetwhich is either a dom node string or an already styled component. Check this line to find the origin of how the
Targettype is defined using Flow. The
tagargument is simply passed through to
constructWithOptionswithout any modifications.
Receiving these two arguments, the
constructWithOptions() function execution returns another function that let’s us create a styled component already considering the
So to close the cycle of
styled.js… Now as we know what the styled function returns and how it is distributed or used for internal construction, we also know better what the different method bodies of the
styled function object methods do.
styled.a works as the
styled(domElement) execution in line 12 of styled.js distributes a “tag-predefined” styled component constructor to it! 🎉
Thx for reading!
As you can see,
styled provides a lot of things. On the one hand a function, on the other hand it acts as an object providing predefined methods for each dom node to build styled components. In my opinion this approach the library provides us to style our components is pure gold.
I hope this post helps you to better understand what styled.js does and how it exposes stuff we can use. Please note all information is based on the Styled-Component’s master branch by Jan 2019. In case there’ll be changes I don’t notice, feel free to contact me in order to update this post.