Published on: 6th May, 2020
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.