How to use CSS-in-JS with Ionic React

Published on: 6th May, 2020

Finally a post related to my work as a Front-End Developer ūüéČ

Let's get started!

Have you tried working with Ionic React and wondered if there was a way to do away with the nasty CSS files and keep all your files in one place? If so, then this blogpost was looking to find you just as much as you were trying to find it!

Disclaimer: I have also just started working with this recently, so I am in no way an expert on this but I can surely help you get started.

This link could also be a helpful pointer.

Things I am assuming about you


  • You have a good idea about React
  • You know CSS-in-JS and CSS in general
  • You would like to control Ionic styles using CSS-in-JS

First things first

Before we jump into setting up CSS-in-JS for our Ionic project, we need to install it first. To install it in your dependencies run
For yarn

yarn add react-jss

For npm
npm install react-jss --save-dev


Onto the good stuff!

Once we have react-jss installed, now we get access to all the methods like ThemeProvider, createUseStyles and such

First, we need to create a file called theme.js, which will house our base themes for the Ionic App. So, create a theme.js  file in your src  forlder and write it up like so.

{
    '@global': {
      ':root': {
        '--ion-background-color':
          'linear-gradient(180deg, #253b40 0%, #000000 100%)', //background color of the app
        '--ion-color-primary': '#E830AB', //primary color used for props as color="primary"
        '--ion-color-secondary': '#56009B', //secondary color user for props as color="secondary"
        '--ion-color-medium': '#3880FF',
        '--ion-font-family': "'Poppins', sans-serif", //Font-family so don't have to import everytime
        '--placeholder-color': 'white',
        '--placeholder-opacity': '1',
      },
      /* Set text color of the entire app for iOS only */
      '.ios': {
        color: 'white',
        '--placeholder-color': 'white',
        '--placeholder-opacity': '1',
      },
  
      /* Set text color of the entire app for Material Design only */
      '.md': {
        color: 'white',
        '--placeholder-color': 'white',
        '--placeholder-opacity': '1',
      },
    },
  };

The root  object is what takes all the global properties of the app

To provide a theme to your <IonApp/>, we need to introduce the <ThemeProvider>  in our App component which will take the root styles as props. So our App component will look somethig like this


import React, { useEffect } from 'react';
import { Switch, Route } from 'react-router-dom';
import { IonApp, IonContent, IonHeader, IonFooter } from '@ionic/react';
import { createUseStyles, ThemeProvider } from 'react-jss';
import '@ionic/react/css/core.css';
import rootStyles from '../../styles/theme';
import Home from './scenes/Home';
import About from './scenes/About';

const useTheme = createUseStyles(rootStyles);
function App({ setAuthToken, loading }) {
  const theme = useTheme();
  return (
    <>
      <ThemeProvider theme={theme}>
        <IonApp>
          <IonHeader />
          <IonContent>
            <Switch>
              <Route exact path="/" component={Home} />
              <Route
                exact
                path="/about"
                component={About}
              />
            </Switch>
          </IonContent>
          <IonFooter no-border>
            <footer />
          </IonFooter>
        </IonApp>
      </ThemeProvider>
    </>
  );
}

What we did above is take the theme  object and pass it down as props to our <IonApp/>  and hence it propagates the styles down as props. This done by assigning the theme object to theme() variable by calling the createUseStyles () function in react-jss


Custom styles for each component

Now, since we have a theme  defined and this will be the starting styles of any component that we later define, we can write custom CSS-in-JS  styles for each component by calling the createUseStyles()  function. I will show you an example below of a custom component as well. This component renders an image with an <IonicChip/>  on the top and <IonicButton/>  at the bottom

import React from 'react';
import {
  IonGrid,
  IonRow,
  IonCol,
  IonImg,
  IonButton,
  IonChip,
  IonLabel,
} from '@ionic/react';
import { createUseStyles } from 'react-jss';

const useStyles = createUseStyles({
  grid: {
    display: 'flex',
    flexDirection: 'column',
    height: '80vh',
    justifyContent: 'space-evenly',
  },
  header: {
    fontSize: '12px',
    textAlign: 'center',
    paddingTop: '15%',
  },
  description: {
    color: 'white',
    textAlign: 'center',
    fontFamily: 'Poppins',
    '& h1': {
      fontSize: '26px',
      lineHeight: '32px',
    },
    '& p': {
      fontSize: '16px',
      lineHeight: '16px',
    },
  },
  sendButton: {
    position: 'absolute',
    bottom: '0px',
    width: '100%',
    left: '0px',
    padding: '0 20px',
    marginBottom: '10px',
  },
  image: {
    height: '240px',
    margin: '16% 0',
  },
  chip: {
    width: '85%',
    margin: '0 6%',
  },
  chipLabel: {
    margin: '0 auto',
  },
});

const WithChip = ({
  image,
  chipText,
  descriptionHeader,
  descriptionText,
  onClickFunc,
  chipOutline,
  chipColor,
  buttonText,
}) => {
  const classes = useStyles();

  return (
    <div>
      <IonGrid className={classes.grid}>
        <IonRow>
          <IonCol className={classes.header}>
            <IonChip
              className={classes.chip}
              outline={chipOutline}
              color={chipColor || 'success'}
            >
              <IonLabel className={classes.chipLabel}>
                {chipText || 'Replace this chip text'}
              </IonLabel>
            </IonChip>
          </IonCol>
        </IonRow>
        <IonRow>
          <IonCol>
            <IonImg
              className={classes.image}
              src={image}
              alt="Replace this image"
            />
          </IonCol>
        </IonRow>
        <IonRow>
          <IonCol className={classes.description}>
            <h1>{descriptionHeader || 'Replace this header'}</h1>
            <p>{descriptionText || 'Replace this description'}</p>
          </IonCol>
        </IonRow>
        <IonRow>
          <IonCol>
            <IonButton
              color="primary"
              size="medium"
              expand="full"
              onClick={onClickFunc}
            >
              {buttonText}
            </IonButton>
          </IonCol>
        </IonRow>
      </IonGrid>
    </div>
  );
};

Some pitfalls

Overriding styles

From time to time, you will find yourself trying to find the specific property to override a style of an Ionic component. To achieve this, you will have to look at the documentation of that specific component and look at the CSS property usually starting with '--'. You need to wrap the component in a parent element, usually a <div/> and give it the CSS style by overriding the property from the documentation. Usually, like so

 const styles = {
   wrapper:{
       '--background-color':'black';
    }
};

Constant use of !important

You will also find it helpful that some problems might be solved by using the !important keyword. Althought, this is highly discouraged in normal CSS, I believe for CSS-in-JS since we have dynamic styles, it will only affect the component that you are passing the class down to. Please correct me if I am wrong on the aforementioned statement.


I hope you found this blogpost at least a tad bit helpful. If you have any further questions I might not have addressed please feel free to email them to me at aminlimbada94@gmail.com. Until next time!