Thursday, 16 November, 2017 UTC


Summary

If you are new to React, you may be confused by the multitude of ways to style components. In this article, we’ll explore the different approaches, their pros and cons, and how you use them in practical, every-day applications.
We’ll start with the original but less-common methods and work our way up to the more modern, best-practice methods:
  • Global CSS files: the CSS files live completely separately from the component files a la typical HTML and CSS
  • Javascript Stylesheets: each component has a Javascript object representing its styles which lives in the same .js component file and is applied in the styles attribute
  • Modular Stylesheets: each component gets its own .css file which lives alongside and is imported into the .js component file and applied in the className attribute to allow for scoped class names
  • Stylized Components: using frameworks such as glamorous, emotion, or styled-components to create clean, modular, and re-usable building blocks
Global CSS Files
In this method, all of the application’s styles are defined in one or more .css files which live completely separately from any of the .js component files. This practice is unfortunately common due to the mindset cultivated by many back-end frameworks which still encourage a separate folder for front-end assets such as .css and .js files. Instead of being able to scope styles to individual components, specificity is achieved through traditional CSS practices of combinations of class names.
A typical folder structure might look something like this:
Global CSS File Folder Structure
src/ styles/ gator.css bite.css components/ Gator.js Bite.js
The render code would look very similar to regular HTML:
Global CSS Classes
render() { return ( <div className="gator container"> ... <div> ) }
Unfortunately, keeping the files separate is not only unnecessary, but actually leaves a lot of potential benefits (such as scoped styles) on the table. This means that by using this method, it is still possible to have the same name conflicts and unexpected side-effects that you would encounter in regular HTML and CSS.
Javascript Stylesheets
In this method, a component’s style definitions are located inside the .js component file itself. They are defined using a regular Javascript object which takes a bit of getting used to at first. This is the first step away from global style definition and towards component-specific styles. While this can be used in web projects through libraries like radium or aphrodite, it is the default way to apply styles in react-native components.
Using Javascript Styles in React Native
const styles = StyleSheet.create({ fontSize: "12pt", margin: "25px auto", padding: "5px" }); ... render() { return ( <View style={styles.container}> ... </View> ) }
Modular Stylesheets
In this method, the a component’s stylesheet is co-located with, and imported inside, the .js component file. This not only keeps the stylesheets clean and readable, but also allows for scoped class names: a useful trick wherein React creates a unique class name behind the scenes to ensure that there are no global style clashes. This means that you can use the same class name in different components without ever worrying about conflicts.
Bonus: with this method, you can use pre-processing libraries like sass and less to define variables, create modules, and clean up your styles.
A typical folder structure for this approach might look something like this:
Modular Stylesheets Folder Structure
src/ components/ Gator/ index.js styles.css Bite/ index.js styles.css
From within each of the components, you simply import the stylesheet and use each class in the className attribute to take advantage of React scoped styles:
Using Modular Styles from the Gator/index.js Component
import styles from './styles' ... render() { return ( <div className={styles.container}> ... </div> ) }
If you use this method and inspect the raw HTML, you will see something like <div class="Gator--container_7a1i0" />. That is React scoping the class name to avoid conflicts. Some of the downsides of this method, though, are that in order to combine classes, or to have conditional classes, you have to use a library like classnames.
Stylized Components
This method is becoming the new de facto way to style React components due to the fact that it encourages the creation of clean, modular, and re-usable building blocks which combine HTML and CSS into one powerful package. Instead of creating generic HTML tags inside your render function and applying class names from a separate CSS file, you create specific “stylized components” which encapsulate that style as part of their definition.
For example, using a library like glamorous, you might do something like this:
Using Stylized Components
const Container = glamorous.div({ fontSize: "12pt", margin: "25px auto", padding: "5px" }) const Header = glamorous.h1({ fontSize: "24pt", fontWeight: "bold" }) const Link = glamorous.a({ textDecoration: "none", ({ primary }) => ({ color: primary ? primaryLink : defaultLink, ":hover": { textDecoration: 'underline' } }) }) ... render() { return ( <Container> <Header>Alligator.io</Header> <Link href="https://alligator.io/" primary>Click me</Link> </Container> ) }
You can think of these stylized components as miniature React components. However, rather than creating separate .js and .css files for something that does not have any custom business or render logic, stylized components allow you to create these components in a clean, modular, and re-usable way.
Bonus: the pointer function inside the Link component allows for custom logic based on the props passed to the stylized component, including conditional values such as used with color, or pseudo-classes such as with :hover.
Conclusion
Applying styles to React components has definitely evolved from the early days of Global CSS Files, through Javascript Stylesheets and Modular Stylesheets, and finally to today’s Stylized Components. While Stylized Components may not work for every situation, in general the React community is heading that direction and finding that it allows for clean, modular, and re-usable combinations of HTML and CSS without having to create separate component files.
👉 For more information about popular CSS-in-JS libraries, including some different Stylized Components packages, check out this companion Alligator.io article:
CSS in JS Roundup: Styling React Components