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.
This method involves two classNames and applies one based on a condition.
.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
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.
.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;
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;
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;
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;
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"
}
}
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;