DEV Community

JD Brewer-Hofmann
JD Brewer-Hofmann

Posted on

Getting Started in Next.js, part 2 - styling

Review

In part 1 we built a basic Next.js site with some pages, and a navigation bar, but it doesn't look like much yet. In part 2 we will explore the different styling options and how to implement them.

Layout Component

Before we apply any styles directly to the existing elements, we can do some refactoring that will save us time in the long run. By using the Next Layout Component, we can share styles, or a general layout, across many pages.

Add a layout.js file to your components folder

And this code

export default function Layout({ children }) {
   return (
       <div>
           <p>layout</p>
           {children}
       </div>
   )
}
Enter fullscreen mode Exit fullscreen mode

Then import Layout into the Posts page, and change the wrapper of the component from a fragment, to a component.

import Navbar from '../components/navbar.js'
import Layout from '../components/layout'

export default function Posts(){
   return(
       <Layout>
           <Navbar />
           <div>
               <h1>Posts</h1>
           </div>
       </Layout>
   )
}
Enter fullscreen mode Exit fullscreen mode

You should see the word layout at the top of your posts page now. We can utilize the layout component to drop our Navbar component into each page in a cleaner way.

If we alter layout.js looks like this

import Navbar from '../components/navbar.js'

export default function Layout({ children }) {
   return (
       <div>
           <Navbar />
           {children}
       </div>
   )
}
Enter fullscreen mode Exit fullscreen mode

And Post.js

import Layout from '../components/layout'

export default function Posts(){
   return(
       <Layout>
           <div>
               <h1>Posts</h1>
           </div>
       </Layout>
   )
}
Enter fullscreen mode Exit fullscreen mode

The post page remains the same, but we are passing our Navbar through our layout wrapper now. Let’s change the other two pages as well.

Let’s add a footer component as well. Creating a /components/footer.js file and some simple code

export default function Footer(){
   return (
       <footer>
           <p>Footer action</p>
       </footer>
   )
}
Enter fullscreen mode Exit fullscreen mode

By adding the footer to the layout component which wraps our other pages, we will now have a footer on every page as well.

import Navbar from '../components/navbar.js'
import Footer from './footer.js'

export default function Layout({ children }) {
   return (

       <div>
           <Navbar />
           {children}
           <Footer />
       </div>
   )
}
Enter fullscreen mode Exit fullscreen mode

We’re ready to scale up now, through our layout component we have added the navbar and footer to each page.

Global CSS

The first place to start styling would be one main CSS file. In Next.js the styles folder contains the a globals.css file for anytime you want to apply styling to every page. Let's add a hover feature to apply to any links on the page.

a:hover {
 text-decoration: underline;
}
Enter fullscreen mode Exit fullscreen mode

Add this block and you’ll have hover functionality on all links now.

The global css file imports to the rest of our project through the pages/_app.js file.

CSS Modules

The first option for adding component level CSS is through CSS modules. There are lots of advantages to using modules, and some frustrations as well, it's best to build some files to see for yourself.

Create a components/layout.module.css file adding this code to it

.container {
   width: 90vw;
   padding: 0 1vmin;
   margin: 5vh auto;
}
Enter fullscreen mode Exit fullscreen mode

Then we will import the new module into our Layout component as 'style' and apply the 'container' class to the div.

import Navbar from '../components/navbar.js'
import styles from './layout.module.css'

export default function Layout({ children }) {
   return (
       <div className={styles.container}>
           <Navbar />
           {children}
       </div>
   )
}
Enter fullscreen mode Exit fullscreen mode

Now, if you take a look at the HTML in your browser’s devtools, you’ll notice that the div rendered by the Layout component has a class name that looks like layout_container__...:

CSS modules automatically generate unique class names. You can avoid any class name collisions by keeping class names scoped locally. An added feature is Next.js's code splitting. Next will only load the needed CSS for each page, which keeps everything running quickly.

Now let’s create a style module for the navbar

Creating a components/navbar.module.css file with the following code

.header {
   display: flex;
   justify-content: space-around;
}
.navlink {
   color: #006000;
}
Enter fullscreen mode Exit fullscreen mode

Importing the navbar.module.css to our navbar component and styling the component with it. We can style our links with a separate class name from the header coming from the same file now.

import Link from 'next/link'
import style from './navbar.module.css'

export default function Navbar(){
   return(
       <header className={style.header}>
           <Link href="/"><a className={style.navlink}>Home</a></Link>
           <Link href="/posts"><a className={style.navlink}>Posts</a></Link>
           <Link href="/about"><a className={style.navlink}>About</a></Link>
       </header>
   )
}
Enter fullscreen mode Exit fullscreen mode

That's the basics of CSS modules. Personally I find modules clunky, and adding multiple class names using interpolation

className={`${styles.description} ${styles.yellow}`}
Enter fullscreen mode Exit fullscreen mode

Just rubs me the wrong way. So let’s investigate more options.

Styled-jsx

Trying a different route with CSS, we have the Styled JSX framework. The style defined for a component only affects that component and nothing else — not even its children!

Next.js includes Styled JSX by default, so getting started is as simple as adding a
'style jsx' tag into an existing React element and writing CSS inside of it.

Let's experiement with the post.js file

import Head from 'next/head'
import Layout from '../components/layout'

export default function Posts(){
   return(
       <Layout>
           <Head>
               <title>Posts</title>
           </Head>
           <div>
               <h1>Posts</h1>
           </div>
           <style jsx>{`
               div {
                   background: #00a000;
               }
               h1 {
                   color: #ffffff;
                   text-align: center;
               }
           }
           `}</style>
       </Layout>
   )
}
Enter fullscreen mode Exit fullscreen mode

ex-stlye-jsx-local-scope

Notice we are using generic selectors, the styles don't affect the same elements or class names in other components. Styled JSX are scoped to this component only (by applying additional unique class names to styled elements).

Check out the unique class name applied to div we styled:

Screen Shot 2021-02-09 at 1.40.29 PM

The downside of Styled JSX is by using a template string to write CSS rules, you lose IDE and code editor assistance to write them, and commenting code out becomes difficult.

If Styled JSX intrigues you, there's lots more you can do with it, including adding global styles inside any component file.

Checkout out Next's documentation for more information.

Adding SASS

I'm a SASS fan, and luckily Next.js integrates with SASS very easily. Let's switch all this over to SCSS files now, because that's sort of the point of this article. Quick side note - I'm using Live Sass Compiler which makes all things SASS a breeze and I highly, highly recommend it. Seriously.

First install SASS

yarn add sass
Enter fullscreen mode Exit fullscreen mode

If we switch our components/navbar.module.css file to components.navbar.scss and compile, we have SASS working for us, but now the files are piling up inside our components folder

Screen Shot 2021-02-09 at 9.35.27 AM

Switching the other CSS files to SASS will triple my files, so let’s refactor this.

First, we will create a styles/main.scss - this will import all the other SCSS files so we only compile this one file, and keep everything organized. I will copy all the data from styles/global.css and paste it inside. Then in pages/_app.js we will switch our import from

import '../styles/globals.css'
Enter fullscreen mode Exit fullscreen mode

To

import '../styles/main.css'
Enter fullscreen mode Exit fullscreen mode

Once we compile ( using the live sass compilier ) , that will watch our main.scss file from now on and we don’t have to worry.

Now let’s move our navbar.module.css and layout.module.css files into our styles folder

Rename navbar.module.css to _navbar.scss and rename layout.module.css to _layout.scss
Next, import both into main.scss

@import 'navbar';
@import 'layout';
Enter fullscreen mode Exit fullscreen mode

Change classNames inside our navbar.js file

import Link from 'next/link'

export default function Navbar(){
   return(
       <header className='header'>
           <Link href="/"><a className='navlink'>Home</a></Link>
           <Link href="/posts"><a className='navlink'>Posts</a></Link>
           <Link href="/about"><a className='navlink'>About</a></Link>
       </header>
   )
}
Enter fullscreen mode Exit fullscreen mode

By creating a corresponding SCSS file for each component, we've developed a very scalable file structure going forward. And by importing each component SCSS file into the main.scss file, we only have to compile once, and we can sit back and enjoy all the beauty of styling with SASS.

Conclusion

That's a lot of reorganizing files, but for me I have a firm understanding of when I why I would use each of these styling options. I think Styled JSX is a great place to start when building an app, but as things scale up, migrating to SASS and moving everything to the style folder appears to be the best option for myself.

As always, don't take my word for any of this. There's some amazing tutorials out there, and Next.js's own documentation is stellar.

Next.js documentation

Discussion (0)