Tuesday, September 27, 2022

An Introduction to CSS-in-JS

CSS-in-JS is a new approach to styling where JavaScript is used to generate CSS for components. It provides several benefits, such as the abstraction of CSS to the component level itself, and the ability to describe styles in a declarative and maintainable way. This article will present some of the benefits of CSS-in-JS, list some popular libraries, and demonstrate its usage by employing the JSS authoring tool.

Web Application Frameworks and CSS-in-JS

Angular, React, Vue, and other frameworks are all based on modules called “components” from which you can build up an entire single-page application (SPA). A component is usually a UI element such as a button, pop-up, or navigation bar. You only need to create a component once and you can reuse it throughout the application. The modularized architecture of modern web apps has made styling more challenging that it used to be. Due to the cascading nature of Cascading Style Sheets (CSS), style sheets can load in any order and override each other in a variety of unexpected combinations. Another problem in modern web apps is that it’s extremely difficult to manage dependencies once your modular web app hits even a moderate level of complexity.

That’s where CSS-in-JS libraries come in. CSS-in-JS bundles each JavaScript component with all its associated CSS rules and dependencies. As a result, components can run independently, without relying on any external CSS file. CSS-in-JS provides several other benefits, including:

  • Leveraging the full power of the JavaScript to support very dynamic styling.
  • Scoped selectors: CSS has just one global namespace, so it’s virtually impossible to avoid selector collisions in non-trivial applications. CSS-in-JS generates unique class names (unless deliberately overridden) when it compiles to CSS.
  • CSS rules are automatically vendor-prefixed, so developers/users don’t have to think about it.
  • Code sharing: constants and functions are easily shared between JavaScript and CSS.
  • Only the styles which are currently in use on user’s screens are in the DOM.

Read: How to Use JavaScript’s CSS Selectors

Two Types of CSS-in-JS Libraries

A few CSS-in-JS libraries are specifically tailored to the React framework. These would include Styled JSX, styled-components, and Stitches. Many other libraries are framework-agnostic, making them fairly easy to integrate into any project, whether built using a component-based framework like Angular, or even vanilla JavaScript. Emotion, Treat, TypeStyle, Fela, JSS, and Goober are all examples of framework-agnostic libraries.

Using JSS to Style an Angular Component

To get a taste of CSS-in-JS in action, we’ll refactor the Using an Angular Service to Read Sass Variables Demo using the JSS library. We will not be rewriting the Color Service or touching anything in the main App Component. Rather, we will focus our efforts on the Feed Component, which receives its colors as input parameters. As such, its CSS is somewhat minimal, but also dynamic, as colors may be selected by the user:

CSS-in-JS Tutorial

 

In this web development tutorial, developers will convert the app to use JSS. Then, in the next installment, we will implement dynamic rule updating.

Read: HTML, CSS, and JavaScript Tools and Libraries

The styles Object in JSS

Just like CSS and SCSS, it still makes sense to put styles in their own file. In this case, we will call it feed.component.styles.ts and put it in the same folder as the other Feed Component files. It governs the appearance of the News Image SVG, which was previously the purview of the feed.component.scss file. CSS-in-JS – in particular JSS – defines its styles much in the same way as SaSS. For instance, it supports nesting (at least with an extra plugin), and the use of the ampersand (&) symbol to refer to the current class (much like the this pointer in JavaScript). You can see both of these features below in the :hover and :focus pseudo-classes:

export const styles: Object = {
  newsImage: {
    cursor: 'pointer',
    marginTop: '25px',
    display: 'flex',
    width: '10rem',
    height: '10rem',
    marginRight: '0.6rem',
    marginLeft: '0.8rem',
    borderRadius: '1rem',
    backgroundColor: data => data.newsImage.backgroundColor,
    '&:hover': {
      backgroundColor: data => data.newsImage['&:hover'].backgroundColor,
    },
    '&:focus': {
      'border-color': data => data.newsImage['&:focus'].borderColor
    }
  }
};

Other than that, the styles are format is basically an Object defined in JavaScript Object Notation, or as it is more commonly known, JSON. Hence, whatever applies to JSON will also apply to your style objects. You can express your keys in camelCase or within quotes, if you’re partial to the standard CSS notation.

Read: Using an Angular Service to Read SaSS Variables

Required Imports for JSS Feed Components

In the Feed Component, we’ll need four imports:

  1. The JSS Library
  2. The jss-plugin-nested library which I alluded to above
  3. Our styles object
  4. Some default plugins and settings, courtesy of the jss-preset-default lib
import jss, { StyleSheet } from 'jss';
import jssPluginNested from 'jss-plugin-nested';
import { styles } from "./feed.component.styles";
import preset from 'jss-preset-default';

Generating a Style Sheet in JSS

Before we generate a style sheet from our style object, we first have to tell JSS to use the jss-preset-default library and set it up with the default presets.

The method to generate the style sheet is called createStyleSheet(). It accepts the styles object as well as some additional options. We will not be going over all of the options here, but we will need to get into them in the next article.

Once you have created a style sheet, its rules will not be applied until you insert it into the render tree. You can get very specific about where in the DOM it gets appended, but for that, you need a Style Sheets Manager. Most of the time, you can just call the attach() method, which appends the style sheet as the last element in the document HEAD:

private stylesheet: StyleSheet;

ngOnInit(): void {
  jss.use(jssPluginNested());
  jss.setup(preset());
  
  // Compile styles, apply plugins.
  this.stylesheet = jss.createStyleSheet(styles).attach();
}

Once attached, you can see the generated style sheet in the browser dev tools. It can be identified by the data-jss attribute:

Attached Stylesheets in JSS

 

Referencing Generated Classes in JSS

Part of the appeal of CSS-in-JS is that it avoids the typical CSS problem where everything is global by default. JSS accomplishes this by generating unique class names, thus completely removing the need for naming conventions. Taking our newsImage object as an example, JSS will generate a class such as newsImage-0-0-1. Subsequent classes would be incremented like anotherClass-0-0-2, etc… JSS keeps track of all the generated class names in the StlyeSheet’s classes attribute, which we can store these in a public variable to reference from our templates:

public classes: Object;

ngOnInit(): void {
  jss.use(jssPluginNested());
  jss.setup(preset());
  
  //...
  this.classes = this.stylesheet.classes;
}

Class names are stored using the original name as the key, so in our case, classes.newsImage will reference its styles:

Generated Class in JSS

 

Exploring the Demo

You will find a working demo on stackblitz.com. It includes the setting of dynamic variables so you can get a preview of next week’s web development tutorial. In the meantime, it is a great way to familiarize yourself with JSS and CSS-in-JS in order to envision whether or not it could be a worthy addition to your web apps.

Read more cascading style sheets (CSS) web development tutorials.

Previous articleHTML Formatting Tags
Next articleHTML Attributes
Rob Gravelle
Rob Gravelle
Rob Gravelle resides in Ottawa, Canada, and has been an IT guru for over 20 years. In that time, Rob has built systems for intelligence-related organizations such as Canada Border Services and various commercial businesses. In his spare time, Rob has become an accomplished music artist with several CDs and digital releases to his credit.

Popular Articles

Featured