Next.js Blog Tutorial - Part 2
Create blog posts and navigate to them with a dropdown menu.
Starting code: https://replit.com/@buckldav/next-tut-1.
Creating Blog Folder and Files
In the pages/
folder, create a blog/
folder with two files, post1.js
and post2.js
.
pages/
blog/
post1.js
post2.js
Creating Posts
Make Post 1 like the below markup. You can choose what text goes between the tags, but be sure to pick the same tags in this example for this tutorial.
pages/blog/post1.js
import Head from "next/head"
import Image from "next/image"
export default function Post1() {
return (
<main>
<Head>
<title>My Next App | Post 1</title>
<meta name="description" content="Generated by create next app" />
<link rel="icon" href="/favicon.ico" />
</Head>
<article>
<header>
<h1>Post 1</h1>
<p>October 14, 2021</p>
<p>by David Buckley</p>
</header>
<div>
<p>This is some content for my first post.</p>
</div>
</article>
</main>
)
}
Once Post 1 is complete, copy + paste the markup and modify text for Post 2. You can navigate to /blog/post1
and /blog/post2
in your browser to see them.
Interjection - ID selector
So far, we have been mostly using element and class selectors in CSS. Now it’s time to introduce the ID selector. ID’s can be used to identify and select a single element. Here’s an example.
<style>
#hello {
font-size: 60px;
color: green;
font-weight: bold;
font-style: italic;
}
</style>
<p id="hello">Hello</p>
<p>Normal Text</p>
Writing inline style for this single element would look horrific and would be hard to maintain, so using an ID in this case is superior.
<p
style="font-size: 60px; color: green; font-weight: bold; font-style: italic;"
>
Hello
</p>
In our project, we are using an ID as part of a dropdown menu to list our blog posts in the navigation. The ID will allow us to identify the element containing the dropdown in our JavaScript and then show and hide it as appropriate.
Creating a Dropdown in our Navigation
We could list all of our blog posts horizontally in our navigation, but this would not scale well. Instead, we will make a dropdown menu where all blog posts are listed. Here’s what the final product will look like:
components/Nav.js
Remember how components can have interactivity (written in JavaScript)? We are going to add a dropdown()
function that runs anytime the dropdown menu is toggled (shown/hidden).
NOTE: This way of selecting the element using
getElementById
in thedropdown()
function is not “Reactive”, meaning that there are more idiomatic ways to do this in a React or Next project (check outuseState
in React’s docs). However, this way of toggling a CSS class will work in any frontend project, so that’s why it is presented.
This is what your entire Nav.js
file should look like:
import Link from "next/link"
import styles from "../styles/components/Nav.module.css"
export default function Nav() {
function dropdown() {
document.getElementById("blogDropdown").classList.toggle(styles.show)
}
return (
<nav className={styles.nav}>
<Link href="/">Home</Link>
<Link href="/about">About</Link>
<div className={styles.dropdown}>
<button className={styles.dropBtn} onClick={dropdown}>
Blog
</button>
<div id="blogDropdown" className={styles.dropContent}>
<Link href="/blog/post1">Post 1</Link>
<Link href="/blog/post2">Post 2</Link>
</div>
</div>
</nav>
)
}
styles/components/Nav.module.css
We need to add some styles to our CSS module in order to make this work. Add the below code after the existing styles in our CSS file.
/* The container <div> - needed to position the dropdown content */
.dropdown {
position: relative;
display: inline-block;
}
/* Dropdown Button */
.dropBtn {
display: inline-block;
color: #0070f3;
padding: 1em;
background-color: transparent;
border: none;
font-size: inherit;
font-family: inherit;
cursor: pointer;
}
/* Dropdown Content (Hidden by Default) */
.dropContent {
display: none;
position: absolute;
background-color: #f1f1f1;
min-width: 160px;
box-shadow: 0px 8px 16px 0px rgba(0, 0, 0, 0.2);
z-index: 1;
}
/* Links inside the dropdown */
.dropContent a {
display: block;
}
/* Show the dropdown menu (use JS to add this class to the .dropContent container when the user clicks on the dropdown button) */
.show {
display: block;
}
CSS Concepts
CSS Display
We’ve already talked about CSS Display if you are in App & Web Development class at Merit. display: block
means the element takes up the full width of its parent. display: inline-block
means the element is rendered inline with its adjacent elements, but can have Box Model styling applied to it. Note that .dropContent
has display: none;
, meaning that the element is not rendered. If the element has the classes dropContent
and show
, the display: block
rule on the show
class overrides the display: none
, thus rendering the dropdown menu on the screen. That’s why the JavaScript function dropdown()
in our Nav component toggles the show
class.
CSS Position
By default, elements have position: static
, meaning they are rendered one after another. position: relative
and position: absolute
can be used together to render elements on top of the static flow (like our dropdown menu).
<parent style="position: relative">
<child style="position: absolute" />
</parent>
If these two position rules are used like in the example above, the child element will be rendered below the parent element but on top of the rest of the page.
More Dropdown Examples
Pseudo Selectors
To finish things off, let’s add some pseudo selectors to our navigation CSS. Pseudo selectors allow for us to change the style depending on the state of the element.
The :hover
pseudo selector is triggered whenever the mouse hovers the element.
.nav a:hover,
.nav button:hover {
color: #0053b3;
}
The :focus
and :active
pseudo selectors are for elements that have been clicked on (like our dropdown button).
.nav a:hover,
.nav button:hover,
.nav button:focus,
.nav button:active {
color: #0053b3;
}
More: w3schools CSS Pseudo Classes
Summary
In this part, we created some blog post pages, add our first bit of JavaScript logic to a component, and learned some CSS tricks to help enhance our navigation.
Finished code: https://replit.com/@buckldav/next-tut-2
Extra: Make the blog dropdown menu hide on window click.
This covers a concept outside of the scope of this tutorial page.
// components/Nav.js
import { useEffect } from "react"
// other imports
export default function Nav() {
// dropdown function is above this
useEffect(() => {
window.onclick = function (e) {
if (!e.target.classList.contains(styles.dropBtn))
document.getElementById("blogDropdown").classList.remove(styles.show)
}
}, [])
// return statement is below this
}
Learning Targets
Standard 2.2
- File structure and naming.
Standard 3.3
- Implement an id selector to modify a single element on the page.
- Implement selectors a:link, a:visited, a:active, a:hover.
Standard 3.4
- Use absolute and static to position elements.
Standard 4.2
- Input Controls: Dropdown Lists.
- Navigational Components.