Vue.js has grown a lot in popularity in the past year or so, but I personally ignored it for quite a while. Why? Because I didn’t feel like we needed another JavaScript framework. Not just because I felt JavaScript’s ecosystem was already rather flooded, but also because I felt like all the top frameworks were already becoming very good, so I didn’t think Vue.js or any other competitor would be able to offer anything that would make it worth switching to. But then I saw Vue.js’s Single File Components.

You see, I had grown attached to React’s JSX syntax because it allowed you to code the template right inside the component’s JavaScript file. Then I heard about CSS Modules, and fell in love with the ability to connect the CSS to the JavaScript and HTML template, while also keeping those styles scoped to the component. Some people saw these things as clashing with the practice of “separation of concerns”, but as you work with a component-based system more, you begin to realize that each component is a single concern, not the 3 technologies the component is built with. If you’re still skeptical, here’s a video you can watch that may at the very least help you understand this viewpoint better. Anyway, CSS modules were an amazing tool, but I hated that the CSS couldn’t be in the same file as the rest of the component, and I wasn’t particularly impressed with the other CSS-in-JavaScript solutions that were coming out. HTML could be included in the component’s JavaScript file in an elegant way, why not CSS?

The All In One Solution

Then I saw Single File Components:

{{ msg }}

That’s a simple example of a Single File Component in Vue.js. The files end with the .vue extension and are written like an snippet of HTML with (usually) three tags in them: one for the template inside a template tag, one for the JavaScript that controls the components inside a script tag, and finally there’s a style tag to put all of the component’s styles into.

If you don’t like working with plain old HTML, CSS, or JavaScript, you can add a lang attribute to the tags to specify what language (and therefore which webpack loader or browserify pre-processor should be used to process it), so if you prefer Pug and Stylus, you can write your component like this:

<template lang="pug"> .example {{ msg }} </template> <script> export default { data () { return { msg: 'Hello world!' } } } </script> <style lang="stylus"> .example font-weight: bold </style>

This flexibility means you don’t need to give up your favorite syntax to use Vue.js and its Single File Components.

Scoping CSS To The Component

One of the greatest benefits of CSS Modules was its ability to scope the styles by altering class names during compilation/bundling so that styles wouldn’t leak out and affect other components. If this is the only feature of CSS Modules you want, then all you need is to add the scoped attribute to the style tag, which will convert this HTML and CSS:

Hello

… into something like this:

Hello

As you can see, it adds a special attribute to the tags that match the selector that acts as a unique identifier, and then adds an attribute selector to the CSS that specifies that ID in order to ensure the styles only apply to the correct elements within the scope of this component.

If, however, you want to also use the composition feature of CSS Modules, you’ll want to add the module attribute to the style tag. If you do this, when your code is compiled, a $style property will be added to you component, so you can reference the class names in your template:

Hello

Then, during compilation, that class name will be made unique and $style.my_component will contain a string of that unique class name. Of course, we still haven’t seen any composition, but, as I said, it’s possible:

Hello

/* backgrounds.css */ .dark_background { background-color: #666; } .light_background { background-color: #ddd; }

As you can see, we can compose styles from classes within our component’s style tag and from other css files. Remember, though, that you cannot compose from another component file ( .vue files); just from other CSS or compile-to-CSS files, such as Stylus or SASS files.

Wrap It Up

What do you think? Vue.js and React are relatively similar in a lot of their aspects, but I feel Single File Components is definitely one step ahead of React’s components because they make it simpler to use CSS Modules or even just scoped CSS and keep those styles in the same file as the component they’re affecting.