The easiest way to apply conditional class names and styles is to use the ternary operator. The ternary operator is suitable for simple use cases with two class names. For other use cases, we need different implementations depending on the use case. This article describes several different approaches to applying styles in different situations.
Conditional className's using ternary operator
This method involves two classNames and applies one based on a condition.
Styles.css
.invalid {
font-family: Helvetica;
font-size: 40px;
font-weight: bold;
color: red;
}
.valid {
font-family: Arial;
font-size: 40px;
font-weight: bold;
color: green;
}
import { useState } from "react";
import "./Styles.css"
export const App = () => {
const [valid, setValid] = useState<boolean>(false)
const handleCssClass = () => {
setValid((valid) => !valid)
}
return(
<>
<div onClick={() => handleCssClass()}
className={valid ? "valid" : "invalid"}>Styled
</div>
</>
)
}
export default App;
The above code selects classes valid or invalid based on the state variable valid
.
The same can be written using CSS modules as below. Note the class names. If the class name includes a hyphen, you must retrieve the class name as a map entry, otherwise as an object property. The CSS file name must follow the *.module.css naming convention and import as an alias.
Styles.module.css
.invalidStyle {
font-family: Helvetica;
font-size: 40px;
font-weight: bold;
color: red;
}
.valid-style{
font-family: Arial;
font-size: 40px;
font-weight: bold;
color: green;
}
import { useState } from "react";
import css from "./Styles.module.css"
export const App = () => {
const [valid, setValid] = useState<boolean>(false)
const handleCssClass = () => {
setValid((valid) => !valid)
}
return(
<>
<div onClick={() => handleCssClass()}
className={valid ? css["valid-style"] : css.invalidStyle}>
Styled
</div>
</>
)
}
export default App;
How to append a className conditionally?
You can append multiple classNames using the template literal as listed below.
.invalidStyle {
font-family: Helvetica;
font-size: 40px;
font-weight: bold;
color: red;
}
.valid-style{
font-family: Arial;
font-size: 40px;
font-weight: bold;
color: green;
}
.divStyleValid {
background-color: rgb(20, 237, 85);
}
.divStyleInvalid {
background-color: rgb(237, 193, 13);
}
import { useState } from "react";
import css from "./Styles.module.css"
export const App = () => {
const [valid, setValid] = useState<boolean>(false)
const handleCssClass = (val: boolean) => {
setValid(val)
}
return(
<>
<div className={valid ? `${css["valid-style"]} ${css.divStyleValid}` : `${css.invalidStyle} ${css.divStyleInvalid}`}>Styled</div>
<button onClick={() => handleCssClass(true)}>Valid</button>
<button onClick={() => handleCssClass(false)}>Invalid</button>
</>
)
}
export default App;
Handling complex conditional className selections
If your className selection logic is more complex than what the ternary operator can handle, you can use if-else statements to select the suitable className.
.belowRange {
background-color: rgb(255, 255, 0);
}
.onRange{
background-color: green;
}
.overRange {
background-color: red;
}
import { useState } from "react";
import css from "./Styles.module.css"
export const App = () => {
const [style, setStyle] = useState<string>()
const handleCssClass = (e: React.ChangeEvent<HTMLInputElement>) => {
const value: number = +e.target.value
if(value < 100){
setStyle(css.belowRange)
}
else
if(value <= 124){
setStyle(css.onRange)
}
else{
setStyle(css.overRange)
}
}
return(
<>
<div>
<label>Enter Deposit Amount: </label>
<input name="amount" type="number" onChange={(e) => handleCssClass(e)} className={style}/>
</div>
</>
)
}
export default App;
Conditional css styles using ternary operator
We can use the ternary operator to apply styles conditionally. But unlike the className property, the style property accepts an object.
import { useState } from "react";
export const App = () => {
const [value, setValue] = useState<number>(0)
return(
<>
<div>
<label>Enter Deposit Amount: </label>
<input name="amount" type="number"
onChange={(e) => setValue(+e.target.value)}
style={value < 100 ? {backgroundColor: "green"} : {backgroundColor: "white"}}
/>
</div>
</>
)
}
export default App;
Handling CSS styles too long to be inline
The above method uses the ternary operator and is suitable for less complex short styles. For longer and multiple styles, we can use style objects.
import { useState } from "react";
export const App = () => {
const [value, setValue] = useState<number>(0)
return(
<>
<div>
<label>Enter Deposit Amount: </label>
<input name="amount" type="number" onChange={(e) => setValue(+e.target.value)} style={value < 100 ? styles.lessThan : styles.greaterThan}/>
</div>
</>
)
}
export default App;
interface StyleSheet {
[key: string]: React.CSSProperties;
}
const styles: StyleSheet = {
lessThan: {
backgroundColor: "green",
border: "0px solid black"
},
greaterThan: {
backgroundColor: "white",
border: "2px solid black"
}
}
Adding and removing CSS styles conditionally
We can use a typescript object to handle more complex style manipulations. That way, we can delegate the selection logic to Javascript and keep the JSX lean and clean.
import { useState } from "react";
export const App = () => {
interface DynamicStyle {
[key: string]: string;
}
const inlineStyle: DynamicStyle = {}
const [value, setValue] = useState<number>(0)
if(value < 100){
inlineStyle.backgroundColor = "yellow"
inlineStyle.border = "2px solid black"
}
else
if(value < 124){
inlineStyle.backgroundColor = "green"
inlineStyle.border = "0px solid black"
}
else
{
inlineStyle.backgroundColor = "pink"
inlineStyle.border = "2px solid black"
}
return(
<>
<div>
<label>Enter Deposit Amount: </label>
<input name="amount" type="number" onChange={(e) => setValue(+e.target.value)} style={inlineStyle}/>
</div>
</>
)
}
export default App;