Defining context-specific styles for subcomponents
i.e. benefits of using variables as selectors for components
File structure
components/
button/
index.styl
index.js
message-box/
index.styl
index.js
We have two components: button and message-box. Message box component includes button as a submit button and needs to define a margin-top
of 1em
for it. Our HTML will look something like this:
<message-box>
<input type="text" />
<button>Submit message</button>
</message-box>
Now, the usual way to define context-specific styles for a subcomponent would be to use the selector of the subcomponent inside the main component's (message-box in our case) style file like this
// components/message-box/index.styl
.message-box
.button
margin-top 10px
But if we decide later on to change the .button
selector to something else we might end up breaking our message-box component's styles.
Here's a version of our button component with its selector turned in to a variable. The reason why I'm still using regular selector with the message-box component is that it's not used anywhere else yet. I would only turn selectors into variables if the component is referenced in another file.
// components/button/index.styl
$button = '.my-awesome-button'
{$button}
background #ddd
border-radius 3px
border 1px solid #ccc
// components/message-box/index.styl
@include '../button'
.message-box
{$button}
margin-top 10px
I decided to prefix my component selector variable with $
to make the difference between regular variables and component selectors clearer. Stylus supports dashes and underscores in variable names so it's also possible to create BEM-style selector variables for subcomponents like $message-box__input
Do I still need to duplicate selectors between index.js and index.styl?
Yes you do. In my opinion this isn't such a big problem. It's definitely something that should be taken into consideration and one could cook up something with stylus's .define() for example. Rather than blindly focusing on the duplication itself I would focus on the fact that we aren't using the same selectors all around our codebase anymore. Now our selectors would only be used inside the component's directory.