Eugene fishing

Building a Responsive Next.js Website Using Tailwind CSS

On this blog post, I'll be documenting the steps taken to build a static responsive Next.js website using Tailwind CSS.

This is a work in progress, and currently, the app looks like this.

Table of Contents

Creating & Starting a Next.js app

  1. I opened Visual Studio Code, opened a new terminal, and I made a new directory:
terminal
mkdir nextjs-tailwindcss
  1. Then, I navigated into it:
terminal
cd nextjs-tailwindcss
  1. Then, I checked if I had Node installed:
terminal
node -v

My terminal outputted:

v20.9.0
  1. Then, I created a new Next.js app using create-next-app:
terminal
npx create-next-app@latest .

I answered No to all of questions that were prompted:

terminal
Need to install the following packages:
create-next-app@14.0.2
Ok to proceed? (y) y
✔ Would you like to use TypeScript? … No
✔ Would you like to use ESLint? … No
✔ Would you like to use Tailwind CSS? … No
✔ Would you like to use `src/` directory? … No
✔ Would you like to use App Router? (recommended) … No
✔ Would you like to customize the default import alias (@/*)? … No

When you don't use the new App Router (recommended), the pages directory is available and on the contrary, when using the App Router, the pages directory isn't available.

The App Router is new and I'll have to explore using the App Router in a future post without the pages directory, and see how things work alternatively.

  1. After the new Next.js app was created, I started the Next.js development server:
terminal
npm run dev
  1. Then, I accessed the Next.js app via my web browser by navigating to:
browser
http://localhost:3000

At this point, a Next.js app boilerplate website is displayed.

Clean-up Process (so we can start developing from scratch)

  1. To start developing from scratch without the files, content, and styles provided by Next.js, I first deleted the CSS module used to style the Home component in the /nextjs-tailwindcss/pages/index.js file which is the entry point to the app:
/nextjs-tailwindcss/styles
Home.module.css
  1. Right after, I received the following "Failed to compile" error in the browser because /nextjs-tailwindcss/pages/index.js was importing the CSS module that was just deleted in the last step:
browser
./styles/Home.module.css
Error: ENOENT: no such file or directory, open '/Users/eugene/Desktop/nextjs-tailwindcss/styles/Home.module.css'

Import trace for requested module:
./styles/Home.module.css
./pages/index.js
  1. Therefore, I removed the import statment from the index.js file:
/nextjs-tailwindcss/pages/index.js
import Head from 'next/head'
import Image from 'next/image'
import { Inter } from 'next/font/google'
- import styles from '@/styles/Home.module.css'
  1. Then, I got a "Unhandled Runtime Error" because the index.js file was trying to access styles in the import statement we just deleted in the last step:
browser
  14 |   <link rel="icon" href="/favicon.ico" />
  15 | </Head>
> 16 | <main className={`${styles.main} ${inter.className}`}>
     |                    ^
  17 |   <div className={styles.description}>
  18 |     <p>
  19 |       Get started by editing&nbsp;
  1. Therefore, I deleted the entire main element, and lines 2, 3, and 5 from the index.js file since I won't be needing any of them:
/pages/index.js
import Head from 'next/head'
- import Image from 'next/image'
- import { Inter } from 'next/font/google'

- const inter = Inter({ subsets: ['latin'] })

export default function Home() {
  return (
    <>
      <Head>
        <title>Create Next App</title>
        <meta name="description" content="Generated by create next app" />
        <meta name="viewport" content="width=device-width, initial-scale=1" />
        <link rel="icon" href="/favicon.ico" />
      </Head>
-     <main className={`${styles.main} ${inter.className}`}>
-       <div className={styles.description}>
-         <p>
-           Get started by editing&nbsp;
-           <code className={styles.code}>pages/index.js</code>
-         </p>
-         <div>
-           <a
-             href="https://vercel.com?utm_source=create-next-app&utm_medium=default-template&utm_campaign=create-next-app"
-             target="_blank"
-             rel="noopener noreferrer"
-           >
-             By{' '}
-             <Image
-               src="/vercel.svg"
-               alt="Vercel Logo"
-               className={styles.vercelLogo}
-               width={100}
-               height={24}
-               priority
-             />
-           </a>
-         </div>
-       </div>
-
-       <div className={styles.center}>
-         <Image
-           className={styles.logo}
-           src="/next.svg"
-           alt="Next.js Logo"
-           width={180}
-           height={37}
-           priority
-         />
-       </div>
-
-       <div className={styles.grid}>
-         <a
-           href="https://nextjs.org/docs?utm_source=create-next-app&utm_medium=default-template&utm_campaign=create-next-app"
-           className={styles.card}
-           target="_blank"
-           rel="noopener noreferrer"
-         >
-           <h2>
-             Docs <span>-&gt;</span>
-           </h2>
-           <p>
-             Find in-depth information about Next.js features and&nbsp;API.
-           </p>
-         </a>
-
-         <a
-           href="https://nextjs.org/learn?utm_source=create-next-app&utm_medium=default-template&utm_campaign=create-next-app"
-           className={styles.card}
-           target="_blank"
-           rel="noopener noreferrer"
-         >
-           <h2>
-             Learn <span>-&gt;</span>
-           </h2>
-           <p>
-             Learn about Next.js in an interactive course with&nbsp;quizzes!
-           </p>
-         </a>
-
-         <a
-           href="https://vercel.com/templates?framework=next.js&utm_source=create-next-app&utm_medium=default-template&utm_campaign=create-next-app"
-           className={styles.card}
-           target="_blank"
-           rel="noopener noreferrer"
-         >
-           <h2>
-             Templates <span>-&gt;</span>
-           </h2>
-           <p>
-             Discover and deploy boilerplate example Next.js&nbsp;projects.
-           </p>
-         </a>
-
-         <a
-           href="https://vercel.com/new?utm_source=create-next-app&utm_medium=default-template&utm_campaign=create-next-app"
-           className={styles.card}
-           target="_blank"
-           rel="noopener noreferrer"
-         >
-           <h2>
-             Deploy <span>-&gt;</span>
-           </h2>
-           <p>
-             Instantly deploy your Next.js site to a shareable URL
-             with&nbsp;Vercel.
-           </p>
-         </a>
-       </div>
-     </main>
    </>
  )
}
  1. Now, the index.js file only contained the following code:
/nextjs-tailwindcss/pages/index.js
import Head from 'next/head'

export default function Home() {
  return (
    <>
      <Head>
        <title>Create Next App</title>
        <meta name="description" content="Generated by create next app" />
        <meta name="viewport" content="width=device-width, initial-scale=1" />
        <link rel="icon" href="/favicon.ico" />
      </Head>
    </>
  )
}

  1. Then, I went to the globals.css file that's being imported into the /nextjs-tailwindcss/pages/_app.js file, and deleted everything:
/nextjs-tailwindcss/styles/globals.css
- :root {
-   --max-width: 1100px;
-   --border-radius: 12px;
-   --font-mono: ui-monospace, Menlo, Monaco, 'Cascadia Mono', 'Segoe UI Mono',
-     'Roboto Mono', 'Oxygen Mono', 'Ubuntu Monospace', 'Source Code Pro',
-     'Fira Mono', 'Droid Sans Mono', 'Courier New', monospace;
- 
-   --foreground-rgb: 0, 0, 0;
-   --background-start-rgb: 214, 219, 220;
-   --background-end-rgb: 255, 255, 255;
- 
-   --primary-glow: conic-gradient(
-     from 180deg at 50% 50%,
-     #16abff33 0deg,
-     #0885ff33 55deg,
-     #54d6ff33 120deg,
-     #0071ff33 160deg,
-     transparent 360deg
-   );
-   --secondary-glow: radial-gradient(
-     rgba(255, 255, 255, 1),
-     rgba(255, 255, 255, 0)
-   );
- 
-   --tile-start-rgb: 239, 245, 249;
-   --tile-end-rgb: 228, 232, 233;
-   --tile-border: conic-gradient(
-     #00000080,
-     #00000040,
-     #00000030,
-     #00000020,
-     #00000010,
-     #00000010,
-     #00000080
-   );
- 
-   --callout-rgb: 238, 240, 241;
-   --callout-border-rgb: 172, 175, 176;
-   --card-rgb: 180, 185, 188;
-   --card-border-rgb: 131, 134, 135;
- }
- 
- @media (prefers-color-scheme: dark) {
-   :root {
-     --foreground-rgb: 255, 255, 255;
-     --background-start-rgb: 0, 0, 0;
-     --background-end-rgb: 0, 0, 0;
- 
-     --primary-glow: radial-gradient(rgba(1, 65, 255, 0.4), rgba(1, 65, 255, 0));
-     --secondary-glow: linear-gradient(
-       to bottom right,
-       rgba(1, 65, 255, 0),
-       rgba(1, 65, 255, 0),
-       rgba(1, 65, 255, 0.3)
-     );
- 
-     --tile-start-rgb: 2, 13, 46;
-     --tile-end-rgb: 2, 5, 19;
-     --tile-border: conic-gradient(
-       #ffffff80,
-       #ffffff40,
-       #ffffff30,
-       #ffffff20,
-       #ffffff10,
-       #ffffff10,
-       #ffffff80
-     );
- 
-     --callout-rgb: 20, 20, 20;
-     --callout-border-rgb: 108, 108, 108;
-     --card-rgb: 100, 100, 100;
-     --card-border-rgb: 200, 200, 200;
-   }
- }
- 
- * {
-   box-sizing: border-box;
-   padding: 0;
-   margin: 0;
- }
- 
- html,
- body {
-   max-width: 100vw;
-   overflow-x: hidden;
- }
- 
- body {
-   color: rgb(var(--foreground-rgb));
-   background: linear-gradient(
-       to bottom,
-       transparent,
-       rgb(var(--background-end-rgb))
-     )
-     rgb(var(--background-start-rgb));
- }
- 
- a {
-   color: inherit;
-   text-decoration: none;
- }
- 
- @media (prefers-color-scheme: dark) {
-   html {
-     color-scheme: dark;
-   }
- }
- 
  1. Then, I deleted the api directory and anything in it since I'm not creating any API routes for this project:
/nextjs-tailwindcss/pages/
api/hello.js
  1. Then, I deleted the following files from the public directory:
/nextjs-tailwindcss/public
favicon.ico
next.svg
vercel.svg
  1. Then, I went back to the browser and saw that there were no more errors, and a blank app where I could start clean from scratch.

Installing Tailwind CSS

  1. Next, I needed to install and setup Tailwind CSS so I navigated over to tailwindcss.com and clicked Get started which directed me over to the Installation page.

  2. Within the Installation page, I clicked the Framework Guides and clicked Next.js.

  3. I skipped down to step 2 of the guide, copied the following command, stopped the development server, and installed Tailwind CSS by pasting, and executing the command:

terminal
npm install -D tailwindcss postcss autoprefixer
  1. Next, I went back to the Tailwind CSS framework guide, copied the next command, and created a Tailwind CSS configuration file and Post CSS configuration file by pasting, and executing the command:
terminal
npx tailwindcss init -p
  1. At this point, the following Tailwind CSS configuration file and Post CSS configuration files were now available in the root of the project folder:
/nextjs-tailwindcss/
tailwind.config.js
postcss.config.js
  1. Then, I went to step 3 of the Tailwind CSS installation guide for Next.js, copied the elements within the content array and pasted them into the content array found inside of the object assigned to module.exports in the tailwind.config.js file:
/nextjs-tailwindcss/tailwind.config.js
/** @type {import('tailwindcss').Config} */
module.exports = {
  content: [
    "./app/**/*.{js,ts,jsx,tsx,mdx}",
    "./pages/**/*.{js,ts,jsx,tsx,mdx}",
    "./components/**/*.{js,ts,jsx,tsx,mdx}",
  
    // Or if using `src` directory:
    "./src/**/*.{js,ts,jsx,tsx,mdx}",
  ],
  theme: {
    extend: {},
  },
  plugins: [],
}
  1. Then, I went to step 4 of the Tailwind CSS installation guide for Next.js, copied the Tailwind directives and pasted them at the top of the globals.css file but commented them out:
/nextjs-tailwindcss/styles/globals.css
// @tailwind base; /* Preflight will be injected here */
// @tailwind components;
// @tailwind utilities;

The Tailwind CSS directives are commented out so they're not taken into effect right now.

Basically, the directive @tailwindcss base will inject Preflight base styles which will serve to reset and standardize styles to ensure a consistent starting point for styling across different browsers and elements.

Soon as these directives are commented back in and the file saved, a noticeable change will be displayed which will be observed in step 34.

  1. Then, I installed a Visual Studio Code extension called Tailwind CSS IntelliSense to assist with Tailwind CSS in the development process.

At this point, Tailwind CSS is almost ready to be used.

Getting a Google Font & Configuring it in a Custom Tailwind CSS Class

  1. Then, I needed a font Tailwind CSS doesn't provide, so I went to Google Fonts, searched for the "Montserrat Alternates" font, selected it, and further selected the following styles:

    • Select Thin 100
    • Select ExtraLight 200
    • Select Light 300
    • Select Regular 400
    • Select Medium 500
    • Select SemiBold 600
    • Select Bold 700
    • Select ExtraBold 800
  2. Once done adding the styles, I copied the import statement that was generated by Google Fonts under "Use on the Web" and pasted it at the top of the globals.css file as such:

/nextjs-tailwindcss/styles/globals.css
@import url('https://fonts.googleapis.com/css2?family=Montserrat+Alternates:wght@100;200;300;400;500;600;700;800&display=swap');
// @tailwind base; /* Preflight will be injected here */
// @tailwind components;
// @tailwind utilities;
  1. Then, I went to the tailwind.config.js file, and extended the Tailwind CSS theme so the "Montserrat Alternates" font can be used with Tailwind CSS:
/nextjs-tailwindcss/tailwind.config.js
/** @type {import('tailwindcss').Config} */
module.exports = {
  content: [
    "./app/**/*.{js,ts,jsx,tsx,mdx}",
    "./pages/**/*.{js,ts,jsx,tsx,mdx}",
    "./components/**/*.{js,ts,jsx,tsx,mdx}",
  
    // Or if using `src` directory:
    "./src/**/*.{js,ts,jsx,tsx,mdx}",
  ],
  theme: {
    extend: {
      fontFamily: {
        'html': ['Montserrat Alternates', 'Arial', 'sans-serif']
      }
    },
  },
  plugins: [],
}

I added a new key called "fontFamily" and assigned it a new object in the "extend" object which is in the "theme" object.

Then, I added a new key called "html" in the "fontFamily" object and assiged it a new array of fonts which includes the "Montserrat Alternates" font that was imported earlier into the globals.css file in step 27 along with a couple fallback fonts.

At this point, the "Montserrat Alternates" font is ready to be applied using the custom Tailwind CSS that was just configured.

Building the Hero Component

  1. Now, to create the banner or hero section at the top of the webpage, I created a components folder at the root of the project directory:
/nextjs-tailwindcss/
components
  1. Then, I created a Hero.jsx file within it:
/nextjs-tailwindcss/components/
Hero.jsx
  1. Then, in the Hero.jsx file, I defined the basic structure of the Hero functional component and exported it so other modules or components could import it:
/nextjs-tailwindcss/components/Hero.jsx
export default function Hero() {
  return (
    <>
      {/* Hero Container */}
      <div className=''>

        {/*Hero Background Image */}

        {/*Hero Background Overlay */}
        <div className='' />

        {/*Hero Content */}
        <div className=''>
          <h2 className=''>Heading</h2>
          <p className=''>Message</p>
          <button className=''>Button</button>
        </div>
      </div>
    </>
  );
};
  1. Then, in the index.js file, I imported the Home component and instantiated it.
/nextjs-tailwindcss/pages/index.js
import Head from 'next/head'
import Hero from '../components/Hero';

export default function Home() {
  return (
    <>
      <Head>
        <title>Create Next App</title>
        <meta name="description" content="Generated by create next app" />
        <meta name="viewport" content="width=device-width, initial-scale=1" />
        <link rel="icon" href="/favicon.ico" />
      </Head>
      <Hero />
    </>
  )
}

  1. Then, I started the Next.js development server:
terminal
npm run serve

At this point, the browser is displaying the Hero content.

Styling and Setting the Background Image of the Hero Component

  1. Now that content is rendered in the browser, I started the styling process by uncommenting the Tailwind CSS directives (added and immediately commented out in step 24) in the global.css file:
/nextjs-tailwindcss/styles/globals.css
@import url('https://fonts.googleapis.com/css2?family=Montserrat+Alternates:wght@100;200;300;400;500;600;700;800&display=swap');
@tailwind base; /* Preflight will be injected here */
@tailwind components;
@tailwind utilities;

Soon as the globals.css was saved, the styling was removed because of Tailwind CSS's Preflight base styling being applied on line 2 of the globals.css file.

/nextjs-tailwindcss/styles/globals.css
@import url('https://fonts.googleapis.com/css2?family=Montserrat+Alternates:wght@100;200;300;400;500;600;700;800&display=swap');
@tailwind base; /* Preflight will be injected here */
@tailwind components;
@tailwind utilities;

The Tailwind CSS directive for base styleing removes styling so there isn't any styling despite having used a h2, p, and a button element in the Hero component which intrinsically has styling.

  1. Then, I went to the _document.js file, added a className with the "font-html" custom Tailwind CSS class that was configured in step 28, and a "scroll-smooth" Tailwind CSS class to the Html element:
/nextjs-tailwindcss/pages/_document.js
import { Html, Head, Main, NextScript } from 'next/document'

export default function Document() {
  return (
    <Html lang="en" className='font-html scroll-smooth'>
      <Head />
      <body>
        <Main />
        <NextScript />
      </body>
    </Html>
  )
}

The "html" key that was added under the "fontFamily" object associated to the "Montserrat Alternates" font in the tailwind.config.js file is now being applied by using the "font-html" Tailwind CSS custom class.

Additionally, the "smooth-scroll" Tailwind CSS class has been applied so scrolling will be animated and gradual rather than instantaneous when navigating to an achor within the page.

Furthermore, if you hover over the class names (e.g. "font-html" or "scroll-smooth"), the CSS definition is displayed via the Visual Code extension, Tailwind CSS IntelliSense, installed in step 25, so you know what Tailwind CSS is doing underneath the hood in terms of CSS.

Soon as the tailwind.config.js file is saved, notice how the font, 'Montserrat Alternates', and the smooth scrolling behavior is applied.

  1. Then, in the Hero.jsx file, I added a className with "relative" to give the div element underneath the comment that says "Hero Container" a position of relative to create a new positioning context for its descendants:
/nextjs-tailwindcss/components/Hero.jsx
export default function Hero() {
  return (
    <>
      {/* Hero Container */}
      <div className='relative'>

        {/*Hero Background Image */}

        {/*Hero Background Overlay */}
        <div className='' />

        {/*Hero Content */}
        <div className=''>
          <h2 className=''>Heading</h2>
          <p className=''>Message</p>
          <button className=''>Button</button>
        </div>
      </div>
    </>
  );
};

The descendants of the Hero Container are the Hero Background Image, the Hero Background Overlay, and the Hero Content.

With the Hero Container having a position of relative, the descendants or children can now be positioned relative to its parent, the Hero Container, and allows the use of z-index to assign each child a stacking order since the children will be stacked on top of each other, first starting with the Hero Background Image, then second, the Background Overlay, and third, the Hero Content.

  1. Then, I added a "flex" class to the "Hero Container" to make it a flex container:
/nextjs-tailwindcss/components/Hero.jsx
export default function Hero() {
  return (
    <>
      {/* Hero Container */}
      <div className='relative flex'>

        {/*Hero Background Image */}

        {/*Hero Background Overlay */}
        <div className='' />

        {/*Hero Content */}
        <div className=''>
          <h2 className=''>Heading</h2>
          <p className=''>Message</p>
          <button className=''>Button</button>
        </div>
      </div>
    </>
  );
};

The flex Tailwind CSS class is be used to set the layout of the Hero component so the elements can be positioned as needed.

  1. Now, I can justify the content horizontally center of the webpage by adding a "justify-center":
/nextjs-tailwindcss/components/Hero.jsx
export default function Hero() {
  return (
    <>
      {/* Hero Container */}
      <div className='relative flex justify-center'>

        {/*Hero Background Image */}

        {/*Hero Background Overlay */}
        <div className='' />

        {/*Hero Content */}
        <div className=''>
          <h2 className=''>Heading</h2>
          <p className=''>Message</p>
          <button className=''>Button</button>
        </div>
      </div>
    </>
  );
};

The content is now centered horizontally along the x-axis.

  1. Then, I added a h-full since I had to set the height of the div to 100% of the view port or screen so I could position the content vertically centered across the full height of the screen:
/nextjs-tailwindcss/components/Hero.jsx
export default function Hero() {
  return (
    <>
      {/* Hero Container */}
      <div className='relative flex justify-center h-full'>

        {/*Hero Background Image */}

        {/*Hero Background Overlay */}
        <div className='' />

        {/*Hero Content */}
        <div className=''>
          <h2 className=''>Heading</h2>
          <p className=''>Message</p>
          <button className=''>Button</button>
        </div>
      </div>
    </>
  );
};
  1. Now, that the Hero Container div element has a vertical height of 100%, I can set the content centered vertically along the y-axis of the viewport or screen by adding "items-center":
/nextjs-tailwindcss/components/Hero.jsx
export default function Hero() {
  return (
    <>
      {/* Hero Container */}
      <div className='relative flex justify-center h-full items-center'>

        {/*Hero Background Image */}

        {/*Hero Background Overlay */}
        <div className='' />

        {/*Hero Content */}
        <div className=''>
          <h2 className=''>Heading</h2>
          <p className=''>Message</p>
          <button className=''>Button</button>
        </div>
      </div>
    </>
  );
};

Now, the Hero content is centered vertically along the y-axis.

  1. Next, I added margin to the bottom of the div element by applying "mb-12" as to give room for the section below:
/nextjs-tailwindcss/components/Hero.jsx
export default function Hero() {
  return (
    <>
      {/* Hero Container */}
      <div className='relative flex justify-center h-full items-center mb-12'>

        {/*Hero Background Image */}

        {/*Hero Background Overlay */}
        <div className='' />

        {/*Hero Content */}
        <div className=''>
          <h2 className=''>Heading</h2>
          <p className=''>Message</p>
          <button className=''>Button</button>
        </div>
      </div>
    </>
  );
};

Now the Hero component has a bottom margin of 48 pixels or 3 rem or 3 times larger than the root element's font size of 16 pixels.

  1. Next, I moved my attention to the inner div element for the Background Image, imported the Image component provided by Next.js and added a self-closing Image element underneath the comment that says Hero Background Image:
/nextjs-tailwindcss/components/Hero.jsx
import Image from 'next/image';

export default function Hero() {
  return (
    <>
      {/* Hero Container */}
      <div className='relative flex justify-center h-screen items-center mb-12'>

        {/* Hero Background Image */}
        <Image />

        {/* Hero Background Overlay */}
        <div className='' />

        {/* Hero Content */}
        <div className=''>
          <h2 className=''>Heading</h2>
          <p className=''>Message</p>
          <button className=''>Button</button>
        </div>
      </div>
    </>
  );
};
  1. Next, I needed an image for the background so I found an image, copied it, and pasted it into a new "images" directory in the "public" directory at the root of the app:
/nextjs-tailwindcss/public/
images/convictlake.jpg
  1. Next, I imported the image into the Hero.jsx file and assigned it to a "src" property of the Image element:
/nextjs-tailwindcss/components/Hero.jsx
import Image from 'next/image';
import heroBackgroundImage from '../public/images/convictlake.jpg';

export default function Hero() {
  return (
    <>
      {/* Hero Container */}
      <div className='relative flex justify-center h-screen items-center mb-12'>

        {/* Hero Background Image */}
        <Image src={heroBackgroundImage} />

        {/* Hero Background Overlay */}
        <div className='' />

        {/* Hero Content */}
        <div className=''>
          <h2 className=''>Heading</h2>
          <p className=''>Message</p>
          <button className=''>Button</button>
        </div>
      </div>
    </>
  );
};

At this point, the Hero Background Image is positioned to the left of the Hero Content because they are flex items.

  1. To position the Background Image to entirely fill its parent Hero Container div element, I added a "fill" property and assigned it to "true" to the Image element:
/nextjs-tailwindcss/components/Hero.jsx
import Image from 'next/image';
import heroBackgroundImage from '../public/images/convictlake.jpg';

export default function Hero() {
  return (
    <>
      {/* Hero Container */}
      <div className='relative flex justify-center h-screen items-center mb-12'>

        {/* Hero Background Image */}
        <Image
          src={heroBackgroundImage}
          fill='true'
        />

        {/* Hero Background Overlay */}
        <div className='' />

        {/* Hero Content */}
        <div className=''>
          <h2 className=''>Heading</h2>
          <p className=''>Message</p>
          <button className=''>Button</button>
        </div>
      </div>
    </>
  );
};

At this point, the Hero Background Image is filling the entire parent Hero Container div element and is displayed on top of the Hero Content which is no longer visible because it is behind the Hero Background Image now.

  1. Next, I needed the background image to scale as the screen size changes, so I added a className property with an "object-cover":
/nextjs-tailwindcss/components/Hero.jsx
import Image from 'next/image';
import heroBackgroundImage from '../public/images/convictlake.jpg';

export default function Hero() {
  return (
    <>
      {/* Hero Container */}
      <div className='relative flex justify-center h-screen items-center mb-12'>

        {/* Hero Background Image */}
        <Image
          src={heroBackgroundImage}
          fill='true'
          className='object-cover'
        />

        {/* Hero Background Overlay */}
        <div className='' />

        {/* Hero Content */}
        <div className=''>
          <h2 className=''>Heading</h2>
          <p className=''>Message</p>
          <button className=''>Button</button>
        </div>
      </div>
    </>
  );
};

Now, when you adjust the screen size from small to big, the Hero Background Image preserves its aspect ratio.

  1. When I decreased the width of the screen, I wanted to display the left side of the image and not the right so I added a "object-left":
/nextjs-tailwindcss/components/Hero.jsx
import Image from 'next/image';
import heroBackgroundImage from '../public/images/convictlake.jpg';

export default function Hero() {
  return (
    <>
      {/* Hero Container */}
      <div className='relative flex justify-center h-screen items-center mb-12'>

        {/* Hero Background Image */}
        <Image
          src={heroBackgroundImage}
          fill='true'
          className='object-cover object-left'
        />

        {/* Hero Background Overlay */}
        <div className='' />

        {/* Hero Content */}
        <div className=''>
          <h2 className=''>Heading</h2>
          <p className=''>Message</p>
          <button className=''>Button</button>
        </div>
      </div>
    </>
  );
};
  1. Next, I added an "alt" property and assigned it a string describing the image.
/nextjs-tailwindcss/components/Hero.jsx
import Image from 'next/image';
import heroBackgroundImage from '../public/images/convictlake.jpg';

export default function Hero() {
  return (
    <>
      {/* Hero Container */}
      <div className='relative flex justify-center h-screen items-center mb-12'>

        {/* Hero Background Image */}
        <Image
          src={heroBackgroundImage}
          fill='true'
          className='object-cover object-left'
          alt='Eugene fishing'
        />

        {/* Hero Background Overlay */}
        <div className='' />

        {/* Hero Content */}
        <div className=''>
          <h2 className=''>Heading</h2>
          <p className=''>Message</p>
          <button className=''>Button</button>
        </div>
      </div>
    </>
  );
};
  1. Next, I shifted my attention to the Hero Background Overlay and needed to position this child Hero Background Overlay div element to fill its parent Hero Container div element so I added an "absolute" to take it out of the normal document flow, added a "top-0" to position it 0 pixels from the top, a "left-0" to position it 0 pixels from the left, a "right-0" to position it 0 pixels from the right, and a "bottom-0" to position it 0 pixels from the bottom of its parent Hero Container div element, and lastly, added a "bg-black/50" for a black background that has 50% opacity or transparency.
/nextjs-tailwindcss/components/Hero.jsx
import Image from 'next/image';
import heroBackgroundImage from '../public/images/convictlake.jpg';

export default function Hero() {
  return (
    <>
      {/* Hero Container */}
      <div className='relative flex justify-center h-screen items-center mb-12'>

        {/* Hero Background Image */}
        <Image
          src={heroBackgroundImage}
          fill='true'
          className='object-cover object-left'
          alt='Eugene fishing'
        />

        {/* Hero Background Overlay */}
        <div className='absolute top-0 left-0 right-0 bottom-0 bg-black/50' />

        {/* Hero Content */}
        <div className=''>
          <h2 className=''>Heading</h2>
          <p className=''>Message</p>
          <button className=''>Button</button>
        </div>
      </div>
    </>
  );
};

Now a black background that's 50% transparent completely overlays the background image.

  1. Next, I shifted my attention to the child Hero Content div element and since it wasn't behaving as I'd expected in terms of its stacking order, I added a "z-0" to explicitly give it a stacking order of 0 to have it stacked on top of the Hero Background Image and the Hero Background Overlay:
/nextjs-tailwindcss/components/Hero.jsx
import Image from 'next/image';
import heroBackgroundImage from '../public/images/convictlake.jpg';

export default function Hero() {
  return (
    <>
      {/* Hero Container */}
      <div className='relative flex justify-center h-screen items-center mb-12'>

        {/* Hero Background Image */}
        <Image
          src={heroBackgroundImage}
          fill='true'
          className='object-cover object-left'
          alt='Eugene fishing'
        />

        {/* Hero Background Overlay */}
        <div className='absolute top-0 left-0 right-0 bottom-0 bg-black/50' />

        {/* Hero Content */}
        <div className='z-0'>
          <h2 className=''>Heading</h2>
          <p className=''>Message</p>
          <button className=''>Button</button>
        </div>
      </div>
    </>
  );
};
  1. Next, I added a "text-white" to change the color of the text to white:
/nextjs-tailwindcss/components/Hero.jsx
import Image from 'next/image';
import heroBackgroundImage from '../public/images/convictlake.jpg';

export default function Hero() {
  return (
    <>
      {/* Hero Container */}
      <div className='relative flex justify-center h-screen items-center mb-12'>

        {/* Hero Background Image */}
        <Image
          src={heroBackgroundImage}
          fill='true'
          className='object-cover object-left'
          alt='Eugene fishing'
        />

        {/* Hero Background Overlay */}
        <div className='absolute top-0 left-0 right-0 bottom-0 bg-black/50' />

        {/* Hero Content */}
        <div className='z-0 text-white'>
          <h2 className=''>Heading</h2>
          <p className=''>Message</p>
          <button className=''>Button</button>
        </div>
      </div>
    </>
  );
};
  1. Next, I added a "p-5" to give the Hero Content a padding of 20 pixels or 1.25 rem or 1.25 times larger than the root element's font size of 16 pixels.
/nextjs-tailwindcss/components/Hero.jsx
import Image from 'next/image';
import heroBackgroundImage from '../public/images/convictlake.jpg';

export default function Hero() {
  return (
    <>
      {/* Hero Container */}
      <div className='relative flex justify-center h-screen items-center mb-12'>

        {/* Hero Background Image */}
        <Image
          src={heroBackgroundImage}
          fill='true'
          className='object-cover object-left'
          alt='Eugene fishing'
        />

        {/* Hero Background Overlay */}
        <div className='absolute top-0 left-0 right-0 bottom-0 bg-black/50' />

        {/* Hero Content */}
        <div className='z-0 text-white p-5'>
          <h2 className=''>Heading</h2>
          <p className=''>Message</p>
          <button className=''>Button</button>
        </div>
      </div>
    </>
  );
};
  1. Next, I added a "text-center" to center align the text for each descendant in the Hero Content div element:
/nextjs-tailwindcss/components/Hero.jsx
import Image from 'next/image';
import heroBackgroundImage from '../public/images/convictlake.jpg';

export default function Hero() {
  return (
    <>
      {/* Hero Container */}
      <div className='relative flex justify-center h-screen items-center mb-12'>

        {/* Hero Background Image */}
        <Image
          src={heroBackgroundImage}
          fill='true'
          className='object-cover object-left'
          alt='Eugene fishing'
        />

        {/* Hero Background Overlay */}
        <div className='absolute top-0 left-0 right-0 bottom-0 bg-black/50' />

        {/* Hero Content */}
        <div className='z-0 text-white p-5 text-center'>
          <h2 className='text-6xl uppercase'>Heading</h2>
          <p className=''>Message</p>
          <button className=''>Button</button>
        </div>
      </div>
    </>
  );
};
  1. Next, I shifted my attention to the first descendant of the Hero Content div element and added a "text-6xl" and an "uppercase" to increase the font size and transform the text to uppercase:
/nextjs-tailwindcss/components/Hero.jsx
import Image from 'next/image';
import heroBackgroundImage from '../public/images/convictlake.jpg';

export default function Hero() {
  return (
    <>
      {/* Hero Container */}
      <div className='relative flex justify-center h-screen items-center mb-12'>

        {/* Hero Background Image */}
        <Image
          src={heroBackgroundImage}
          fill='true'
          className='object-cover object-left'
          alt='Eugene fishing'
        />

        {/* Hero Background Overlay */}
        <div className='absolute top-0 left-0 right-0 bottom-0 bg-black/50' />

        {/* Hero Content */}
        <div className='z-0 text-white p-5 text-center'>
          <h2 className='text-6xl uppercase'>Heading</h2>
          <p className=''>Message</p>
          <button className=''>Button</button>
        </div>
      </div>
    </>
  );
};
  1. Next, I shifted my attention to the second descendant of the Hero Content div element and added a "text-2xl" to increase the font size:
/nextjs-tailwindcss/components/Hero.jsx
import Image from 'next/image';
import heroBackgroundImage from '../public/images/convictlake.jpg';

export default function Hero() {
  return (
    <>
      {/* Hero Container */}
      <div className='relative flex justify-center h-screen items-center mb-12'>

        {/* Hero Background Image */}
        <Image
          src={heroBackgroundImage}
          fill='true'
          className='object-cover object-left'
          alt='Eugene fishing'
        />

        {/* Hero Background Overlay */}
        <div className='absolute top-0 left-0 right-0 bottom-0 bg-black/50' />

        {/* Hero Content */}
        <div className='z-0 text-white p-5 text-center'>
          <h2 className='text-6xl uppercase'>Heading</h2>
          <p className='text-2xl'>Message</p>
          <button className=''>Button</button>
        </div>
      </div>
    </>
  );
};
  1. Next, I shifted my attention to the third descendant of the Hero Content div element and added a "px-6" to give padding on the left and right side, a "py-1" to give padding to the top and bottom, a "border" to give it a border, and a "mt-2" to give it a margin on top.
/nextjs-tailwindcss/components/Hero.jsx
import Image from 'next/image';
import heroBackgroundImage from '../public/images/convictlake.jpg';

export default function Hero() {
  return (
    <>
      {/* Hero Container */}
      <div className='relative flex justify-center h-screen items-center mb-12'>

        {/* Hero Background Image */}
        <Image
          src={heroBackgroundImage}
          fill='true'
          className='object-cover object-left'
          alt='Eugene fishing'
        />

        {/* Hero Background Overlay */}
        <div className='absolute top-0 left-0 right-0 bottom-0 bg-black/50' />

        {/* Hero Content */}
        <div className='z-0 text-white p-5 text-center'>
          <h2 className='text-6xl uppercase'>Heading</h2>
          <p className='text-2xl'>Message</p>
          <button className='px-6 py-1 border mt-2'>Button</button>
        </div>
      </div>
    </>
  );
};
  1. Next, I wanted to dynamically render the text for the first and second descendants of the Hero Content div element so I replaced the text, "Heading" and "Message", with curly braces, for embedding JavaScript expressions in JSX, and added a prop variable for each element so values could be passed to this component from index.js where the Hero component is being instantiated from. Additionally, I added curly braces with both of the prop variables in the paranthesis of the function declaration or function signature to destructure the prop object that's being passed to this component:
/nextjs-tailwindcss/components/Hero.jsx
import Image from 'next/image';
import heroBackgroundImage from '../public/images/convictlake.jpg';

export default function Hero({ heading, message }) {
  return (
    <>
      {/* Hero Container */}
      <div className='relative flex justify-center h-screen items-center mb-12'>

        {/* Hero Background Image */}
        <Image
          src={heroBackgroundImage}
          fill='true'
          className='object-cover object-left'
          alt='Eugene fishing'
        />

        {/* Hero Background Overlay */}
        <div className='absolute top-0 left-0 right-0 bottom-0 bg-black/50' />

        {/* Hero Content */}
        <div className='z-0 text-white p-5 text-center'>
          <h2 className='text-6xl uppercase'>{ heading }</h2>
          <p className='text-2xl'>{ message }</p>
          <button className='px-6 py-1 border mt-2'>Button</button>
        </div>
      </div>
    </>
  );
};
  1. Then, I went to the index.js file, added a "heading" prop, assigned it a string value, added a "message" prop, and assigned it a value:
/nextjs-tailwindcss/pages/index.js
import Head from 'next/head'
import Hero from '../components/Hero';

export default function Home() {
  return (
    <>
      <Head>
        <title>Create Next App</title>
        <meta name="description" content="Generated by create next app" />
        <meta name="viewport" content="width=device-width, initial-scale=1" />
        <link rel="icon" href="/favicon.ico" />
      </Head>
      <Hero heading='Eugene Kim' message='Software Engineer' />
    </>
  )
}

Now, the page is being rendered with text being passed into the Hero component from the entry point of the app, the index.js file.

Building the Navigation Bar Component

  1. To kick start the creation of the navigation bar, I created a new Navbar.jsx file in the components directory and created the foundation of the navigation bar component.

    Essentially, I've declared the variables that'll be needed, some comments where the logic for handling color changes and for opening and closing the mobile menu will be, and the UI portion of the component that'll be rendered.

    The UI portion basically consists of one outer div that'll serve as the outer most container and an inner div for an inner container that'll hold the logo, the links, the mobile menu buttons, and the mobile menu.
/nextjs-tailwindcss/components/Navbar.jsx
export default function Navbar() {
  // The variables for storing the colors of the navigation bar
  const backgroundColor = '';
  const textColor = '';

  // The variable for storing the boolean used for presenting the mobile menu
  const isMobileMenuDislayed = false;

  // The function that will respond to clicks of the mobile menu buttons and presenting the mobile menu

  // The function that will respond to scrolling on the browser window and presenting the colors of the navigation bar

  return (
    <>
      {/* The Navigation Bar Outer Container */}
      <div className={`${backgroundColor}`}>

        {/*The Navigation Bar Inner Container */}
        <div className=''>

          {/*The Navigation Bar Logo */}
          <h1 className={`${textColor}`}>E</h1>

          {/*The Navigation Bar Links */}
          <ul className={`${textColor}`}>
            <li className=''>About</li>
            <li className=''>Work</li>
            <li className=''>Blog</li>
            <li className=''>Contact</li>
          </ul>

          {/*The Mobile Menu Buttons */}
          <div onClick='' className=''>
          {
            isMobileMenuDislayed ? <button className=''>close</button>
            : <button className={`${textColor}`}>open</button>
          }
          </div>

          {/*The Mobile Menu */}
          <div className={ isMobileMenuDislayed ? '' : '' }>
            <ul>
              <li className=''>About</li>
              <li className=''>Work</li>
              <li className=''>Blog</li>
              <li className=''>Contact</li>
            </ul>
          </div>

        </div>

      </div>
    </>
  );
}
  1. Next, to prevent the navigation bar from being scrolled off the viewable part of the screen (the viewport), in the most outer container div, I add some classes and fixed it to the top-left, made the width go across the full width of the viewport, gave it a greater stacking order than the background image so it'll be on top of it, and some animation effects for a smooth and delayed transition when the colors are changed in the navigation bar.
/nextjs-tailwindcss/components/Navbar.jsx
export default function Navbar() {
  // The variables for storing the colors of the navigation bar
  const backgroundColor = '';
  const textColor = '';

  // The variable for storing the boolean used for presenting the mobile menu
  const isMobileMenuDislayed = false;

  // The function that will respond to clicks of the mobile menu buttons and presenting the mobile menu

  // The function that will respond to scrolling on the browser window and presenting the colors of the navigation bar

  return (
    <>
      {/* The Navigation Bar Outer Container */}
      <div className={`${backgroundColor} fixed left-0 top-0 w-full z-10 ease-in duration-300`}>

        {/*The Navigation Bar Inner Container */}
        <div className=''>

          {/*The Navigation Bar Logo */}

          <h1 className={`${textColor}`}>E</h1>
          {/*The Navigation Bar Links */}
          <ul className={`${textColor}`}>
            <li className=''>About</li>
            <li className=''>Work</li>
            <li className=''>Blog</li>
            <li className=''>Contact</li>
          </ul>

          {/*The Mobile Menu Buttons */}
          <div onClick='' className=''>
          {
            isMobileMenuDislayed ? <button className=''>close</button>
            : <button className={`${textColor}`}>open</button>
          }
          </div>

          {/*The Mobile Menu */}
          <div className={ isMobileMenuDislayed ? '' : '' }>
            <ul>
              <li className=''>About</li>
              <li className=''>Work</li>
              <li className=''>Blog</li>
              <li className=''>Contact</li>
            </ul>
          </div>

        </div>

      </div>
    </>
  );
}
  1. Next, I made the inner container div horizontally smaller than the outer most container div by giving it a fixed width and even margins to the left and right.

    Furthermore, I positioned the logo, the links, the mobile menu buttons, and the mobile menu all next to each other, side-by-side horizontally, centered them horizontally and vertically, and gave them padding within the div.
/nextjs-tailwindcss/components/Navbar.jsx
export default function Navbar() {
  // The variables for storing the colors of the navigation bar
  const backgroundColor = '';
  const textColor = '';

  // The variable for storing the boolean used for presenting the mobile menu
  const isMobileMenuDislayed = false;

  // The function that will respond to clicks of the mobile menu buttons and presenting the mobile menu

  // The function that will respond to scrolling on the browser window and presenting the colors of the navigation bar

  return (
    <>
      {/* The Navigation Bar Outer Container */}
      <div className={`${backgroundColor} fixed left-0 top-0 w-full z-10 ease-in duration-300`}>

        {/*The Navigation Bar Inner Container */}
        <div className='max-w-[1240px] m-auto flex justify-between items-center p-4'>

          {/*The Navigation Bar Logo */}
          
          <h1 className={`${textColor}`}>E</h1>
          {/*The Navigation Bar Links */}
          <ul className={`${textColor}`}>
            <li className=''>About</li>
            <li className=''>Work</li>
            <li className=''>Blog</li>
            <li className=''>Contact</li>
          </ul>

          {/*The Mobile Menu Buttons */}
          <div onClick='' className=''>
          {
            isMobileMenuDislayed ? <button className=''>close</button>
            : <button className={`${textColor}`}>open</button>
          }
          </div>

          {/*The Mobile Menu */}
          <div className={ isMobileMenuDislayed ? '' : '' }>
            <ul>
              <li className=''>About</li>
              <li className=''>Work</li>
              <li className=''>Blog</li>
              <li className=''>Contact</li>
            </ul>
          </div>

        </div>

      </div>
    </>
  );
}
  1. Next, I made the logo bigger and bold.
/nextjs-tailwindcss/components/Navbar.jsx
export default function Navbar() {
  // The variables for storing the colors of the navigation bar
  const backgroundColor = '';
  const textColor = '';

  // The variable for storing the boolean used for presenting the mobile menu
  const isMobileMenuDislayed = false;

  // The function that will respond to clicks of the mobile menu buttons and presenting the mobile menu

  // The function that will respond to scrolling on the browser window and presenting the colors of the navigation bar

  return (
    <>
      {/* The Navigation Bar Outer Container */}
      <div className={`${backgroundColor} fixed left-0 top-0 w-full z-10 ease-in duration-300`}>

        {/*The Navigation Bar Inner Container */}
        <div className='max-w-[1240px] m-auto flex justify-between items-center p-4'>

          {/*The Navigation Bar Logo */}
          <h1 className={`${textColor} font-bold text-4xl`}>E</h1>

          {/*The Navigation Bar Links */}
          <ul className={`${textColor}`}>
            <li className=''>About</li>
            <li className=''>Work</li>
            <li className=''>Blog</li>
            <li className=''>Contact</li>
          </ul>

          {/*The Mobile Menu Buttons */}
          <div onClick='' className=''>
          {
            isMobileMenuDislayed ? <button className=''>close</button>
            : <button className={`${textColor}`}>open</button>
          }
          </div>

          {/*The Mobile Menu */}
          <div className={ isMobileMenuDislayed ? '' : '' }>
            <ul>
              <li className=''>About</li>
              <li className=''>Work</li>
              <li className=''>Blog</li>
              <li className=''>Contact</li>
            </ul>
          </div>

        </div>

      </div>
    </>
  );
}
  1. Next, I made the navigation links hidden by default but when the screen size is equal to or greater than a small screen size, the ul is made into a flex container, displaying the links horizontally side-by-side.

    You'll notice the navigation bar links aren't visible when the screen is small and appear when the screen size is adjusted to a larger screen size.
/nextjs-tailwindcss/components/Navbar.jsx
export default function Navbar() {
  // The variables for storing the colors of the navigation bar
  const backgroundColor = '';
  const textColor = '';

  // The variable for storing the boolean used for presenting the mobile menu
  const isMobileMenuDislayed = false;

  // The function that will respond to clicks of the mobile menu buttons and presenting the mobile menu

  // The function that will respond to scrolling on the browser window and presenting the colors of the navigation bar

  return (
    <>
      {/* The Navigation Bar Outer Container */}
      <div className={`${backgroundColor} fixed left-0 top-0 w-full z-10 ease-in duration-300`}>

        {/*The Navigation Bar Inner Container */}
        <div className='max-w-[1240px] m-auto flex justify-between items-center p-4'>

          {/*The Navigation Bar Logo */}
          <h1 className={`${textColor} font-bold text-4xl`}>E</h1>

          {/*The Navigation Bar Links */}
          <ul className={`${textColor} hidden sm:flex`}>
            <li className='p-4'>About</li>
            <li className='p-4'>Work</li>
            <li className='p-4'>Blog</li>
            <li className='p-4'>Contact</li>
          </ul>

          {/*The Mobile Menu Buttons */}
          <div onClick='' className=''>
          {
            isMobileMenuDislayed ? <button className=''>close</button>
            : <button className={`${textColor}`}>open</button>
          }
          </div>

          {/*The Mobile Menu */}
          <div className={ isMobileMenuDislayed ? '' : '' }>
            <ul>
              <li className=''>About</li>
              <li className=''>Work</li>
              <li className=''>Blog</li>
              <li className=''>Contact</li>
            </ul>
          </div>

        </div>

      </div>
    </>
  );
}
  1. Next, I added some padding to the li elements to give space between them.
/nextjs-tailwindcss/components/Navbar.jsx
export default function Navbar() {
  // The variables for storing the colors of the navigation bar
  const backgroundColor = '';
  const textColor = '';

  // The variable for storing the boolean used for presenting the mobile menu
  const isMobileMenuDislayed = false;

  // The function that will respond to clicks of the mobile menu buttons and presenting the mobile menu

  // The function that will respond to scrolling on the browser window and presenting the colors of the navigation bar

  return (
    <>
      {/* The Navigation Bar Outer Container */}
      <div className={`${backgroundColor} fixed left-0 top-0 w-full z-10 ease-in duration-300`}>

        {/*The Navigation Bar Inner Container */}
        <div className='max-w-[1240px] m-auto flex justify-between items-center p-4'>

          {/*The Navigation Bar Logo */}
          <h1 className={`${textColor} font-bold text-4xl`}>E</h1>

          {/*The Navigation Bar Links */}
          <ul className={`${textColor} hidden sm:flex`}>
            <li className='p-4'>About</li>
            <li className='p-4'>Work</li>
            <li className='p-4'>Blog</li>
            <li className='p-4'>Contact</li>
          </ul>

          {/*The Mobile Menu Buttons */}
          <div onClick='' className=''>
          {
            isMobileMenuDislayed ? <button className=''>close</button>
            : <button className={`${textColor}`}>open</button>
          }
          </div>

          {/*The Mobile Menu */}
          <div className={ isMobileMenuDislayed ? '' : '' }>
            <ul>
              <li className=''>About</li>
              <li className=''>Work</li>
              <li className=''>Blog</li>
              <li className=''>Contact</li>
            </ul>
          </div>

        </div>

      </div>
    </>
  );
}
  1. Next, I made the mobile menu button hidden and not displayed when the screen size is equal to or greater than a small screen size.

    Now, you'll see the mobile menu button when the screen size is small and won't when the screen size is larger.

    Simultaneously, you'll see the navigation links appear when the screen size is larger because of the change we added in step 63.

    Now, you're able to see how the user will be able to access the mobile menu and the links again by the displayed mobile menu button when the screen is small.
/nextjs-tailwindcss/components/Navbar.jsx
export default function Navbar() {
  // The variables for storing the colors of the navigation bar
  const backgroundColor = '';
  const textColor = '';

  // The variable for storing the boolean used for presenting the mobile menu
  const isMobileMenuDislayed = false;

  // The function that will respond to clicks of the mobile menu buttons and presenting the mobile menu

  // The function that will respond to scrolling on the browser window and presenting the colors of the navigation bar

  return (
    <>
      {/* The Navigation Bar Outer Container */}
      <div className={`${backgroundColor} fixed left-0 top-0 w-full z-10 ease-in duration-300`}>

        {/*The Navigation Bar Inner Container */}
        <div className='max-w-[1240px] m-auto flex justify-between items-center p-4'>

          {/*The Navigation Bar Logo */}
          <h1 className={`${textColor} font-bold text-4xl`}>E</h1>

          {/*The Navigation Bar Links */}
          <ul className={`${textColor} hidden sm:flex`}>
            <li className='p-4'>About</li>
            <li className='p-4'>Work</li>
            <li className='p-4'>Blog</li>
            <li className='p-4'>Contact</li>
          </ul>

          {/*The Mobile Menu Buttons */}
          <div onClick='' className='sm:hidden z-10'>
          {
            isMobileMenuDislayed ? <button className=''>close</button>
            : <button className={`${textColor}`}>open</button>
          }
          </div>

          {/*The Mobile Menu */}
          <div className={ isMobileMenuDislayed ? '' : '' }>
            <ul>
              <li className=''>About</li>
              <li className=''>Work</li>
              <li className=''>Blog</li>
              <li className=''>Contact</li>
            </ul>
          </div>

        </div>

      </div>
    </>
  );
}
  1. Next, I made the close button's text white because I'll be adding a black background to the mobile menu later.
/nextjs-tailwindcss/components/Navbar.jsx
export default function Navbar() {
  // The variables for storing the colors of the navigation bar
  const backgroundColor = '';
  const textColor = '';

  // The variable for storing the boolean used for presenting the mobile menu
  const isMobileMenuDislayed = false;

  // The function that will respond to clicks of the mobile menu buttons and presenting the mobile menu

  // The function that will respond to scrolling on the browser window and presenting the colors of the navigation bar

  return (
    <>
      {/* The Navigation Bar Outer Container */}
      <div className={`${backgroundColor} fixed left-0 top-0 w-full z-10 ease-in duration-300`}>

        {/*The Navigation Bar Inner Container */}
        <div className='max-w-[1240px] m-auto flex justify-between items-center p-4'>

          {/*The Navigation Bar Logo */}
          <h1 className={`${textColor} font-bold text-4xl`}>E</h1>

          {/*The Navigation Bar Links */}
          <ul className={`${textColor} hidden sm:flex`}>
            <li className='p-4'>About</li>
            <li className='p-4'>Work</li>
            <li className='p-4'>Blog</li>
            <li className='p-4'>Contact</li>
          </ul>

          {/*The Mobile Menu Buttons */}
          <div onClick='' className='sm:hidden z-10'>
          {
            isMobileMenuDislayed ? <button className='text-white'>close</button>
            : <button className={`${textColor}`}>open</button>
          }
          </div>

          {/*The Mobile Menu */}
          <div className={ isMobileMenuDislayed ? '' : '' }>
            <ul>
              <li className='p-4 text-4xl hover:text-white'>About</li>
              <li className='p-4 text-4xl hover:text-white'>Work</li>
              <li className='p-4 text-4xl hover:text-white'>Blog</li>
              <li className='p-4 text-4xl hover:text-white'>Contact</li>
            </ul>
          </div>

        </div>

      </div>
    </>
  );
}
  1. Next, I made the mobile menu links bigger, bold, have padding, and white when hovered over.
/nextjs-tailwindcss/components/Navbar.jsx
export default function Navbar() {
  // The variables for storing the colors of the navigation bar
  const backgroundColor = '';
  const textColor = '';

  // The variable for storing the boolean used for presenting the mobile menu
  const isMobileMenuDislayed = false;

  // The function that will respond to clicks of the mobile menu buttons and presenting the mobile menu

  // The function that will respond to scrolling on the browser window and presenting the colors of the navigation bar

  return (
    <>
      {/* The Navigation Bar Outer Container */}
      <div className={`${backgroundColor} fixed left-0 top-0 w-full z-10 ease-in duration-300`}>

        {/*The Navigation Bar Inner Container */}
        <div className='max-w-[1240px] m-auto flex justify-between items-center p-4'>

          {/*The Navigation Bar Logo */}
          <h1 className={`${textColor} font-bold text-4xl`}>E</h1>

          {/*The Navigation Bar Links */}
          <ul className={`${textColor} hidden sm:flex`}>
            <li className='p-4'>About</li>
            <li className='p-4'>Work</li>
            <li className='p-4'>Blog</li>
            <li className='p-4'>Contact</li>
          </ul>

          {/*The Mobile Menu Buttons */}
          <div onClick='' className='sm:hidden z-10'>
          {
            isMobileMenuDislayed ? <button className='text-white'>close</button>
            : <button className={`${textColor}`}>open</button>
          }
          </div>

          {/*The Mobile Menu */}
          <div className={ isMobileMenuDislayed ? '' : '' }>
            <ul>
              <li className='p-4 text-4xl hover:text-white'>About</li>
              <li className='p-4 text-4xl hover:text-white'>Work</li>
              <li className='p-4 text-4xl hover:text-white'>Blog</li>
              <li className='p-4 text-4xl hover:text-white'>Contact</li>
            </ul>
          </div>

        </div>

      </div>
    </>
  );
}
  1. Next, to navigate without full page reloads to other components such as the ones I'll be building for the about, work, blog, and contact sections, I imported the Link component provided by Next.js and wrapped the logo with it along with the route to the Home component, then wrapped each li element's child string/text along with their respective routes.
/nextjs-tailwindcss/components/Navbar.jsx
import Link from 'next/link';

export default function Navbar() {
  // The variables for storing the colors of the navigation bar
  const backgroundColor = '';
  const textColor = '';

  // The variable for storing the boolean used for presenting the mobile menu
  const isMobileMenuDislayed = false;

  // The function that will respond to clicks of the mobile menu buttons and presenting the mobile menu

  // The function that will respond to scrolling on the browser window and presenting the colors of the navigation bar

  return (
    <>
      {/* The Navigation Bar Outer Container */}
      <div className={`${backgroundColor} fixed left-0 top-0 w-full z-10 ease-in duration-300`}>

        {/*The Navigation Bar Inner Container */}
        <div className='max-w-[1240px] m-auto flex justify-between items-center p-4'>

          {/*The Navigation Bar Logo */}
          <Link href='/'>
            <h1 className={`${textColor} font-bold text-4xl`}>E</h1>
          </Link>
          
          {/*The Navigation Bar Links */}
          <ul className={`${textColor} hidden sm:flex`}>
            <li className='p-4'>
              <Link href='/about'>About</Link>
            </li>
            <li className='p-4'>
              <Link href='/work'>Work</Link>
            </li>
            <li className='p-4'>
              <Link href='/blog'>Blog</Link>
            </li>
            <li className='p-4'>
              <Link href='/contact'>Contact</Link>
            </li>
          </ul>

          {/*The Mobile Menu Buttons */}
          <div onClick='' className='sm:hidden z-10'>
          {
            isMobileMenuDislayed ? <button className='text-white'>close</button>
            : <button className={`${textColor}`}>open</button>
          }
          </div>

          {/*The Mobile Menu */}
          <div className={ isMobileMenuDislayed ? '' : '' }>
            <ul>
              <li className='p-4 text-4xl hover:text-white'>
                <Link href='/about'>About</Link>
              </li>
              <li className='p-4 text-4xl hover:text-white'>
                <Link href='/work'>Work</Link>
              </li>
              <li className='p-4 text-4xl hover:text-white'>
                <Link href='/blog'>Blog</Link>
              </li>
              <li className='p-4 text-4xl hover:text-white'>
                <Link href='/contact'>Contact</Link>
              </li>
            </ul>
          </div>

        </div>

      </div>
    </>
  );
}
  1. Next, since I want to trigger a re-render whenever the background color and text color of the navigation bar changes in response to the user scrolling and when the boolean changes in response to the user clicking the mobile menu buttons, I imported the useState function or hook from React.

    Since the useState function returns an array with the state value and a function to update the state value, I used array destructuring to access both of them by using the variable I had initially declared and initialized to assign the state value to and another variable to assign the function to update the state value to.
/nextjs-tailwindcss/components/Navbar.jsx
import Link from 'next/link';
import { useState } from 'react';

export default function Navbar() {
  // The variables for storing the colors of the navigation bar
  const [backgroundColor, setBackgroundColor] = useState('bg-transparent');
  const [textColor, setTextColor] = useState('text-white');

  // The variable for storing the boolean used for presenting the mobile menu
  const [isMobileMenuDislayed, setIsMobileMenuDisplayed] = useState(false);

  // The function that will respond to clicks of the mobile menu buttons and presenting the mobile menu

  // The function that will respond to scrolling on the browser window and presenting the colors of the navigation bar

  return (
    <>
      {/* The Navigation Bar Outer Container */}
      <div className={`${backgroundColor} fixed left-0 top-0 w-full z-10 ease-in duration-300`}>

        {/*The Navigation Bar Inner Container */}
        <div className='max-w-[1240px] m-auto flex justify-between items-center p-4'>

          {/*The Navigation Bar Logo */}
          <Link href='/'>
            <h1 className={`${textColor} font-bold text-4xl`}>E</h1>
          </Link>
          
          {/*The Navigation Bar Links */}
          <ul className={`${textColor} hidden sm:flex`}>
            <li className='p-4'>
              <Link href='/about'>About</Link>
            </li>
            <li className='p-4'>
              <Link href='/work'>Work</Link>
            </li>
            <li className='p-4'>
              <Link href='/blog'>Blog</Link>
            </li>
            <li className='p-4'>
              <Link href='/contact'>Contact</Link>
            </li>
          </ul>

          {/*The Mobile Menu Buttons */}
          <div onClick='' className='sm:hidden z-10'>
          {
            isMobileMenuDislayed ? <button className='text-white'>close</button>
            : <button className={`${textColor}`}>open</button>
          }
          </div>

          {/*The Mobile Menu */}
          <div className={ isMobileMenuDislayed ? '' : '' }>
            <ul>
              <li className='p-4 text-4xl hover:text-white'>
                <Link href='/about'>About</Link>
              </li>
              <li className='p-4 text-4xl hover:text-white'>
                <Link href='/work'>Work</Link>
              </li>
              <li className='p-4 text-4xl hover:text-white'>
                <Link href='/blog'>Blog</Link>
              </li>
              <li className='p-4 text-4xl hover:text-white'>
                <Link href='/contact'>Contact</Link>
              </li>
            </ul>
          </div>

        </div>

      </div>
    </>
  );
}
  1. Next, I wanted to detect the user's scroll movement on the browser then change the colors of the navigation bar when they scrolled past a certain point, so I imported the useEffect hook from React and defined it by passing in a function as an argument, and an empty array as another argument, to have it only execute once after the initial render of the component.

    Within the function that's being passed to the useEffect hook, I added a call to a function provided by the browser's window object for for detecting user interactions, and passed as an argument "scroll" to detect scroll movements and another argument, a variable, that a callback function is assigned to that is executed when scroll movements are detected.

    The callback function is defined above the call to the function provided by the browser by design, and checks if the user scrolled 90 pixels or more down on the browser, and if so, executes the state updater function for changing the state variable for the background color of the navigation bar to white and executes the state updater function for changing the state variable for the text color of the navigation bar to black, otherwise, it executes the same sets of functions but sets the background color to transparent and the text color to white.
/nextjs-tailwindcss/components/Navbar.jsx
import Link from 'next/link';
import { useState, useEffect } from 'react';

export default function Navbar() {
  // The variables for storing the colors of the navigation bar
  const [backgroundColor, setBackgroundColor] = useState('bg-transparent');
  const [textColor, setTextColor] = useState('text-white');

  // The variable for storing the boolean used for presenting the mobile menu
  const [isMobileMenuDislayed, setIsMobileMenuDisplayed] = useState(false);

  // The function that will respond to clicks of the mobile menu buttons and presenting the mobile menu

  // The function that will respond to scrolling on the browser window and presenting the colors of the navigation bar
  useEffect(() => {
    const changeColor = () => {
      if (window.scrollY >= 90) {
        setBackgroundColor('bg-white');
        setTextColor('text-black');
      } else {
        setBackgroundColor('bg-transparent');
        setTextColor('text-white');
      }
    };
    window.addEventListener('scroll', changeColor);
  }, []);

  return (
    <>
      {/* The Navigation Bar Outer Container */}
      <div className={`${backgroundColor} fixed left-0 top-0 w-full z-10 ease-in duration-300`}>

        {/*The Navigation Bar Inner Container */}
        <div className='max-w-[1240px] m-auto flex justify-between items-center p-4'>

          {/*The Navigation Bar Logo */}
          <Link href='/'>
            <h1 className={`${textColor} font-bold text-4xl`}>E</h1>
          </Link>
          
          {/*The Navigation Bar Links */}
          <ul className={`${textColor} hidden sm:flex`}>
            <li className='p-4'>
              <Link href='/about'>About</Link>
            </li>
            <li className='p-4'>
              <Link href='/work'>Work</Link>
            </li>
            <li className='p-4'>
              <Link href='/blog'>Blog</Link>
            </li>
            <li className='p-4'>
              <Link href='/contact'>Contact</Link>
            </li>
          </ul>

          {/*The Mobile Menu Buttons */}
          <div onClick='' className='sm:hidden z-10'>
          {
            isMobileMenuDislayed ? <button className='text-white'>close</button>
            : <button className={`${textColor}`}>open</button>
          }
          </div>

          {/*The Mobile Menu */}
          <div className={ isMobileMenuDislayed ? '' : '' }>
            <ul>
              <li className='p-4 text-4xl hover:text-white'>
                <Link href='/about'>About</Link>
              </li>
              <li className='p-4 text-4xl hover:text-white'>
                <Link href='/work'>Work</Link>
              </li>
              <li className='p-4 text-4xl hover:text-white'>
                <Link href='/blog'>Blog</Link>
              </li>
              <li className='p-4 text-4xl hover:text-white'>
                <Link href='/contact'>Contact</Link>
              </li>
            </ul>
          </div>

        </div>

      </div>
    </>
  );
}
  1. Next, I wanted to use icons instead of using HTML buttons for showing and closing the mobile menu, so I imported a menu icon and a close icon from React Icons then replaced the mobile menu buttons with them.

    Then, on lines 14 - 16, I defined a handler function that executes the state updater function for toggling the boolean that conditionally renders Tailwind CSS classes for the mobile menu buttons and the mobile menu and assigned it to the onclick event handler on the mobile menu buttons div.

    Furthermore, in the ternary operation in the mobile menu div, when the condition is true, I added Tailwind CSS classes to dispaly the mobile menu such that the mobile menu will be hidden on screen sizes larger than the small screen size or larger, taken out of the normal document flow and positioned all the way to the left, all the way to the top, all the way to the right, and all the way to the bottom of the viewport. I also added classes to make the div fit the entire height and width of the viewport, text centered, background black, text white, and animation with a delayed transition when it appears.

    Lastly, I did the same for when the condition is false, but instead of the mobile menu positioned all the way to the left, I made it go -100% from all the way to the left, to make it not visible on the viewport at all.
/nextjs-tailwindcss/components/Navbar.jsx
import Link from 'next/link';
import { useState, useEffect } from 'react';
import { AiOutlineMenu, AiOutlineClose } from 'react-icons/ai';

export default function Navbar() {
  // The variables for storing the colors of the navigation bar
  const [backgroundColor, setBackgroundColor] = useState('bg-transparent');
  const [textColor, setTextColor] = useState('text-white');

  // The variable for storing the boolean used for presenting the mobile menu
  const [isMobileMenuDislayed, setIsMobileMenuDisplayed] = useState(false);

  // The function that will respond to clicks of the mobile menu buttons and presenting the mobile menu
  const handleMobileMenu = () => {
    setIsMobileMenuDisplayed(!isMobileMenuDislayed);
  }

  // The function that will respond to scrolling on the browser window and presenting the colors of the navigation bar
  useEffect(() => {
    const changeColor = () => {
      if (window.scrollY >= 90) {
        setBackgroundColor('bg-white');
        setTextColor('text-black');
      } else {
        setBackgroundColor('bg-transparent');
        setTextColor('text-white');
      }
    };
    window.addEventListener('scroll', changeColor);
  }, []);

  return (
    <>
      {/* The Navigation Bar Outer Container */}
      <div className={`${backgroundColor} fixed left-0 top-0 w-full z-10 ease-in duration-300`}>

        {/*The Navigation Bar Inner Container */}
        <div className='max-w-[1240px] m-auto flex justify-between items-center p-4'>

          {/*The Navigation Bar Logo */}
          <Link href='/'>
            <h1 className={`${textColor} font-bold text-4xl`}>E</h1>
          </Link>
          
          {/*The Navigation Bar Links */}
          <ul className={`${textColor} hidden sm:flex`}>
            <li className='p-4'>
              <Link href='/about'>About</Link>
            </li>
            <li className='p-4'>
              <Link href='/work'>Work</Link>
            </li>
            <li className='p-4'>
              <Link href='/blog'>Blog</Link>
            </li>
            <li className='p-4'>
              <Link href='/contact'>Contact</Link>
            </li>
          </ul>

          {/*The Mobile Menu Buttons */}
          <div onClick={handleMobileMenu} className='sm:hidden z-10'>
          {
            isMobileMenuDislayed ?
              <AiOutlineClose className='text-white' size={20} />
            :
              <AiOutlineMenu className={`${textColor}`} size={20} />
          }
          </div>

          {/*The Mobile Menu */}
          <div className={
            isMobileMenuDislayed ?
              'sm:hidden absolute top-0 left-0 right-0 bottom-0 flex justify-center items-center w-full h-screen bg-black text-center ease-in duration-300 text-white'
            :
              'sm:hidden absolute top-0 left-[-100%] right-0 bottom-0 flex justify-center items-center w-full h-screen bg-black text-center ease-in duration-300 text-white'
          }>
            <ul>
              <li className='p-4 text-4xl hover:text-white'>
                <Link href='/about'>About</Link>
              </li>
              <li className='p-4 text-4xl hover:text-white'>
                <Link href='/work'>Work</Link>
              </li>
              <li className='p-4 text-4xl hover:text-white'>
                <Link href='/blog'>Blog</Link>
              </li>
              <li className='p-4 text-4xl hover:text-white'>
                <Link href='/contact'>Contact</Link>
              </li>
            </ul>
          </div>

        </div>

      </div>
    </>
  );
}