rikukissa
6/23/2015 - 8:28 PM

Defining context-specific styles for subcomponents

Defining context-specific styles for subcomponents

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:

HTML

<message-box>
  <input type="text" />
  <button>Submit message</button>
</message-box>

Problem

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.

Solution

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.