'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.

https://www.npmjs.com/package/clsx

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