Styling allows you to define what your website looks like and create a cohesive and aesthetic brand. Although several approaches use Cascading Style Sheets (CSS) to style web pages, JavaScript-based solutions are more flexible and give you more control than standard CSS.

One popular method is to use JavaScript Style Sheets (JSS), which lets you write CSS styles in JavaScript. JSS has several advantages, including using variables, JavaScript expressions, and functions to create dynamic styles and themes.

This article explores how JSS works, its benefits, and how to use it in your JavaScript applications. It also discusses dynamic styling, theming, and performance optimization. You can use JSS with many kinds of apps, but in this article, we’ll focus on JSS for React.

What Is JSS?

With JSS, you can write CSS styles as JavaScript objects and use these objects as class names in elements or components. JSS is framework-agnostic so you can use it in vanilla JavaScript or with frameworks like React and Angular.

JSS has several advantages over traditional CSS styling:

  • Dynamic styling — With JSS, you can manipulate styles based on user interactions or values such as props or context. JavaScript functions help you dynamically generate styles in the browser depending on the application state, external data, or browser APIs.
  • Improved theming capabilities — You can create styles specific to a particular theme using JSS. For example, you can create styles for a light and dark theme and then apply these theme-specific styles to the entire application according to user preferences. If you’re using React, the React-JSS package supports context-based theme propagation. You can define and manage the theme in one place before passing the theme information down the component tree using a theme provider.
  • Improved maintainability — By defining styles in JavaScript objects, you can group related styles in one location and import them into your application when needed. This approach reduces code duplication and improves code organization, making it easier to maintain styles over time.
  • Real CSS — JSS generates actual CSS rather than inline styles that can be messy and hard to manage. JSS uses unique class names by default, which helps you avoid naming collisions caused by the global nature of CSS.

How To Write Styles With JSS

This article is based on a React project. It uses the react-jss package, which integrates JSS with React using the Hooks API. react-jss comes with the default plugins and lets you use JSS with minimal setup.

Basic Syntax and Use of JSS in React

To use JSS in React, first, install the react-jss package using a package manager such as npm or Yarn.

The syntax for writing styles in JSS involves defining CSS rules for specific elements within a JavaScript object. For example, the following code defines the styles for a button in a React app.


const styles = {
      button: {
            padding: "10px 20px",
            background: "#f7df1e",
            textAlign: "center",
            border:"none"
      }
};

Note: The CSS properties are in camelcase.

To apply these styles to an HTML element:

  1. Generate the classes by passing the styles to the createUseStyles() method from react-jss:
import { createUseStyles } from "react-jss";
const styles = {
       button: {
             padding: "10px 20px",
             background: "#f7df1e",
             textAlign: "center",
             border:"none"
       }
};
const useStyles = createUseStyles(styles);
  1. Apply the CSS to the button element using the generated class name:
const App = () = > {
      const classes = useStyles();
      return (
            < button className={classes.button} > </button >
      );
};

This code creates a React component and applies the styles in the styles object.

How To Handle Pseudo-Classes, Media Queries, and Keyframes

JSS supports all existing CSS features, including pseudo-classes, media queries, and keyframes. Use the same syntax as regular CSS style rules to define styles for these features.

Pseudo-Classes

For example, suppose you want to add a hover pseudo-class to the button to change the background color when a user moves their mouse over it. The following code implements this pseudo-class so the button background turns light green on hover:

const styles = {
      button: {
            padding: "10px 20px",
            background: "#f7df1e",
            textAlign: "center",
            border:"none",
            '&:hover': {
                  backgroundColor: 'lightgreen',
            }
     }
};

Keyframes

Likewise, you can apply a keyframe animation to a component using the @keyframes rule. For example, below is a style object for a spinning component.

const styles = {
       '@keyframes spin': {
             '0%': {
                   transform: 'rotate(0deg)',
             },
             '100%': {
                   transform: 'rotate(360deg)',
             },
       },
       spinner: {
              width: "100px",
              height: "100px",
              backgroundColor: "lightgreen",
              animation: '$spin 1s linear infinite',
       },
}

Within the styles function, you defined a keyframe animation named spin using the @keyframes rule. Then, you create a class called spinner that applies the animation using the $ syntax to reference the keyframe animation.

Media Queries

Media queries also use the usual CSS syntax in JSS. For example, to change a button’s font size at a specific screen size, use the following styles:

const styles = {
      button: {
            fontSize: "12px",
            '@media (max-width: 768px)': {
                  fontSize: '34px',
            },
      }
};

As you’ve just seen, writing styles in JSS isn’t that different to writing plain CSS. However, its advantage is that you can leverage the power of JavaScript to make your styles dynamic.

Dynamic Styling with JSS

Dynamic styling means creating styles that change in response to specific conditions. In React, the styles may change depending on values such as state, props, and component context.

How To Create Dynamic Styles with JSS

In JSS, you can conditionally apply styles to your elements with JavaScript expressions to create dynamic style rules.

Say you have a button that receives a prop called bgColor. Its value is the button’s background color. To create a style rule that changes the button’s background color based on the prop, pass the props to the useStyles method.

import { createUseStyles } from "react-jss"

const styles = {
      button: {
            padding: "10px 20px",
            background: props = >props.bgColor,
            textAlign: "center",
            border:"none"
      }
};
const Button = ({...props}) => {
  
      const useStyles = createUseStyles(styles);
      const classes = useStyles({...props});
      return (
            <button className={classes.button}>Button </button>
      );
};

Then, you can reference the props in the styles object. The example above references props.bgColor.

You can pass the background color you want when you render the component. The component below renders two Button components with lightgreen and yellow background colors.

export default function App() {
  return (
    <div >
      <Button bgColor="lightgreen" />
      <div style={{ marginTop: "10px" }}></div>
      <Button bgColor="yellow" />
    </div>
  );
}
Two buttons dynamically styled with JSS
Two buttons dynamically styled with JSS

Each time you render the Button component, you can style the background as you like.

You can also change the styles based on a component’s state. Suppose you have a navigation menu with several link items. To highlight the link for the current page, define a state value called isActive that keeps track of whether a menu link item is active.

You can then use a JavaScript ternary operator to check the value of isActive, setting the link’s color to blue if the state is true and red if false.

const styles = {
      a: {
             color: ({ isActive }) => isActive ? 'blue' : 'red',
             padding: '10px',
      },
};

Now, active links become blue, inactive links become red.

Similarly, you can create dynamic styling based on context. You may style an element, like UserContext, based on the value of a context that stores the user’s online status.

const { online } = useContext(UserContext);
const styles = {
      status: {
            background: online ? 'lightgreen' : '',
            width: '20px',
            height: '20px',
            borderRadius: "50%",
            display: online ? 'flex' : 'hidden'
      },
};

In this example, the element has a green background if the user is online. You set the display property to flex if the user is online and hidden if the user is offline.

Use Cases for Dynamic Styling

Dynamic styling is a powerful feature of JSS that has many use cases:

  • Theming — You can define styles based on a theme object, such as a light theme and a dark theme, and pass it down to components as a prop or context value.
  • Conditional rendering — JSS lets you define styles based on specific values. You can create styles that only apply under certain conditions — such as when a button is disabled, a text field is in an error state, a side navigation menu is open, or when a user is online.
  • Responsive design — You can use dynamic styling in JSS to change an element’s style based on the viewport’s width. For example, you could define a set of styles for a specific breakpoint using media queries and apply them conditionally based on the screen size.

How To Use Themes with JSS

Use themes to provide a consistent user interface across your whole application. It’s easy to create themes in JSS — simply define a theme object with global style values, such as colors, typography, and spacing. For example:

const theme = {
      colors: {
            primary: '#007bff',
            secondary: '#6c757d',
            light: '#f8f9fa',
            dark: '#343a40',
       },
       typography: {
             fontFamily: 'Helvetica, Arial, sans-serif',
             fontSize: '16px',
             fontWeight: 'normal',
       },
       spacing: {
             small: '16px',
             medium: '24px',
             large: '32px',
       },
};

To apply themes to your components, use context providers. The JSS library provides a ThemeProvider component you can wrap around components that need access to the theme.

The following example wraps the Button with the ThemeProvider component and passes the theme object as a prop.

import { ThemeProvider } from "react-jss";
const App = () => (
      <ThemeProvider theme={theme}>
            <Button />
      </ThemeProvider>
)

You can access the theme in the Button component using a useTheme() hook and pass it to the useStyles object. The example below uses the styles defined in the theme object to create a primary button.

import { useTheme } from “react-jss”

const useStyles = createUseStyles({
  primaryButton: {
    background: ({ theme }) => theme.colors.primary,
    font: ({ theme }) => theme.typography.fontFamily,
    fontSize: ({ theme }) => theme.typography.fontSize,
    padding: ({ theme }) => theme.spacing.medium
  }
});

const Button = () => {
      const theme = useTheme()
      const classes = useStyles({theme})
      return (
            <div>
              <button className={classes.primaryButton}> Primary Button </button>
            </div>

      )
}

The button should look like the image below, with black text on a rectangular, blue button.

A primary button style based on the theme.
A primary button style based on the theme.

If you changed any of the values in the theme object, that would automatically trigger new styles to apply to all components wrapped with the ThemeProvider component. If you change the primary color’s value to lightgreen, the button’s color also changes to light green, like in the image below.

A primary button color adapts to the theme.
A primary button color adapts to the theme.

Here are a few guidelines to follow when creating themes:

  • Define the theme object in a separate file to keep the code organized and easy to maintain.
  • Use descriptive names for style values to make the theme object easy to read and update.
  • Use CSS variables to define values you often use across your CSS.
  • Create default values for all style properties to maintain a consistent design across your application.
  • Thoroughly test your themes to ensure they work as intended on all devices and browsers.

By following these best practices, you’ll create a theme that’s simple to use and easy to update as your application grows.

Performance and Optimization

JSS is a performant styling solution. With JSS, only the styles currently used on-screen are added to the Document Object Model (DOM), which reduces the DOM size and speeds up rendering. JSS also caches rendered styles, which means JSS compiles CSS only once, improving performance even more.

You can take advantage of additional performance optimizations using the react-jss package instead of the JSS core package. For example, react-jss removes the stylesheets when the component is unmounted. It also handles critical CSS extraction and only extracts styles from rendered components. That’s how the react-jss package reduces the CSS bundle size and improves load times.

To further reduce the CSS bundle size, use code splitting to load only the CSS that a specific page or component needs. A library like loadable-components  can simplify code splitting.

JSS also lets you generate CSS server-side. You can aggregate and stringify the attached CSS using the StyleSheet registry class from JSS, then send the rendered components and CSS string to the client. After launching the application, the static CSS is no longer needed, and you can remove it, reducing the bundle size.

Summary

You’ve learned the basics of JSS syntax, how to create and apply style objects to components, and how to create dynamic styles. You also know how to use the ThemeProvider component to apply themes and improve performance in JSS. Now you can use JSS to create reusable, maintainable, and dynamic styles that adapt to various conditions.