'How to add multiple classNames to nextjs elements
I have an unordered list element that looks like this:
<ul className={styles["projects-pd-subdetails-list"]}>
{detail.subdetails.map((sub) => (
<li
className={styles["projects-pd-text projects-pd-subdetail"]}
>
{sub}
</li>
))}
</ul>
With a normal React element, I would be able to apply the multiple classes for the li
element like this:
<li className="projects-pd-text projects-pd-subdetail">{sub}</li>
However, having a space like I do in nextjs means the styles are just getting ignored. How can I fix this problem and properly account for two classNames for my li
element here?
Solution 1:[1]
As stated in my original comment I have not worked with Next.js.
It appears as though styles is a map of some kind i.e.:
const styles = {
"projects-pd-subdetails-list": "Class Name A",
"projects-pd-text": "Class Name B",
"projects-pd-subdetail": "Class Name C"
}
This means that by using a line similar to styles["projects-pd-text projects-pd-subdetail"]
you are attempting to retrieve the value for the key "projects-pd-text projects-pd-subdetail"
which does not exist.
I would suggest retrieving the values individually from the map and then joining them together with your choice of string concatenation.
className={styles["projects-pd-subdetail"] + " " + styles["projects-pd-text"]}
// OR
className={`${styles["projects-pd-subdetail"]} ${styles["projects-pd-text"]}`}
Solution 2:[2]
You can use multiple className
like this
<li className={`${styles.projects-pd-text} ${styles.projects-pd-subdetail}`}>
{sub}
</li>
But there is a problem. It may throws an error(I guess, not sure). You may use camelCase
in your css className.
<li className={`${styles.projectsPdText} ${styles.projectsPdSubdetail}`}>
{sub}
</li>
or, if you don't want to camelCase
<li className={`${styles["projects-pd-text"]} ${styles["projects-pd-subdetail"]}`}>
{sub}
</li>
Let me know if it works.
Solution 3:[3]
A simple array join should suffice.
["class1", "class2", "class3"].join(" ")
result: "class1 class2 class3"
<li className={[styles.projects_pd_text, styles.projects_pd_subdetail].join(" ")}>
{sub}
</li>
Or save it as a variable for multiple uses
const listClasses = [styles.projects_pd_text, styles.projects_pd_subdetail].join(" ")
Solution 4:[4]
clsx is generally used to conditionally apply a given className.
Solution 5:[5]
Because it might be tedious to always write styles.className
for every class you need to add to an element, you can create a utility function that makes things look neater.
For example, in my case, I created this function:
export const classes = (styles: any, classes: string) => {
const list = classes.split(' ');
classes = '';
for (const className of list) {
classes += `${styles[className] }`
}
return classes;
}
in a util file.
And on elements, I can do this
<div className={classes( styles, 'hero-container text-success text-bold italicize another-class yet-another-class ')}>
Lorem ipsum dolor
</div>
A PLUS:
One other issue around classnames I encountered getting started with NextJS on VSCode was getting emmet tag generation to list the classnames the NextJS way when I type css class selector.
"Complete NextJS Classname Emmet": {
"scope": "javascript,typescript,typescriptreact,javascriptreact",
"prefix": ["."],
"body": [
"<div className={classes( styles, '$1')}>",
"\t$2",
"</div>"
],
"description": "Lean autocomplete emmet in nextjs css modules classname"
}
I added this to my VSCode > Preferences > User Snippets > typescriptreact.json
These made working with classnames in NextJS easier for me - especially on VSCode.
Solution 6:[6]
If you console log your css or scss module class (ex. ImportedStyleModule.someClassName) you'll see it's just a string that has an auto generated UID concatenated.
Ergo, it's just a string so you can use a number of ways to join them like so:
//ts
const mergeStyles = (styleArray: string[]) => (styleArray.map((style: string) => `${style}`).join(" "));
//js
const mergeStyles = (styleArray) => (styleArray.map((style) => `${style}`).join(" "));
//example
return (
<span
onClick={() => setIsClicked(!isClicked)}
className={`${!!isClicked
? mergeStyles([NavbarStyle.navButton, NavbarStyle.navButtonOpen])
: NavbarStyle.navButton}`}
>
<Image src='/image-logo.svg' alt='logo' width='80px' height='40px' />
</span>
);
Solution 7:[7]
It worked for me.
<div className={styles.side +" "+ styles.side2}>side2</div>
Thanks to CodenNerd
Solution 8:[8]
This is how it works for me in my style component
<ul>
<li className={router.pathname == "/" && styles.active}><Link href="/">Home</Link></li>
<li className={router.pathname == "/about" && styles.active}><Link href="/about">About</Link></li>
<li className={router.pathname == "/contact" && styles.active}><Link href="/contact">Contact</Link></li>
<li><Link href="/404">404</Link></li>
</ul>
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
Solution | Source |
---|---|
Solution 1 | Jacob Smit |
Solution 2 | |
Solution 3 | rain |
Solution 4 | Prathamesh sawant |
Solution 5 | CodenNerd |
Solution 6 | jason-warner |
Solution 7 | Mausam Kumar Giri |
Solution 8 | Foysal imran |