Skip to content

Scaffolding Solution


Want to see the finished code?

Check out the scaffolding branch of our GitHub repo.

Project Structure

To set up these three pages (/, /signup, and /signin) we create the following project structure.

pro-jokes/
app/
  signin/
    page.jsx  # (1)!
  signup/
    page.jsx  # (2)!
  head.jsx    # (3)!
  layout.jsx  # (4)!
  page.jsx    # (5)!
  Navbar.jsx  # (6)!
  1. export default function SignIn() {
      return (
        <main>
          <h1>Sign in</h1>
    
          <form id="signin_form">
    
            <div>
              <label htmlFor="signin_email">Email</label>
              <input type="email" id="signin_email" required />
            </div>
    
            <div>
              <label htmlFor="signin_password">Password</label>
              <input type="password" id="signin_password" required />
            </div>
    
            <button type="submit">Sign in</button>
    
          </form>
    
          <button>Sign in with Google</button>
    
        </main>
      )
    }
    
  2. export default function SignUp() {
      return (
        <main>
          <h1>Sign up</h1>
    
          <form id="signup_form">
    
            <div>
              <label htmlFor="signup_full_name">Full Name</label>
              <input type="text" id="signup_full_name" required />
            </div>
    
            <div>
              <label htmlFor="signup_email">Email</label>
              <input type="email" id="signup_email" required />
            </div>
    
            <div>
              <label htmlFor="signup_password">Password</label>
              <input type="password" id="signup_password" required />
            </div>
    
            <div>
              <label htmlFor="signup_confirm_password">Confirm password</label>
              <input type="password" id="signup_confirm_password" required />
            </div>
    
            <button type="submit">Sign up</button>
    
          </form>
    
          <button>Sign up with Google</button>
    
        </main>
      )
    }
    
  3. export default function Head() {
      return (
        <>
          <title>Pro Jokes</title>
          <meta content="width=device-width, initial-scale=1" name="viewport" />
          <meta name="description" content="Professional jokes" />
        </>
      )
    }
    
  4. import Navbar from "./Navbar";
    
    export default function RootLayout({ children }) {
      return (
        <html lang="en">
          <head />
          <body>
            <Navbar/>
            {children}
            </body>
        </html>
      )
    }
    
  5. export default function Home() {
      return (
        <main>
          <h1>Pro Jokes</h1>
    
          <hr />
    
          <div>
            <p>Q: What do you call a fake noodle?</p>
            <p>A: An impasta.</p>
          </div>
    
          <hr />
    
          <div>
            <p>Q: Why do bees have sticky hair?</p>
            <p>A: Because they use a honeycomb.</p>
          </div>
    
          <hr />
    
          <div>
            <p>Q: Why did the scarecrow get promoted?</p>
            <p>A: He was outstanding in his field.</p>
          </div>
    
        </main>
      )
    }
    
  6. import Link from "next/link";
    
    
    export default function Navbar() {
        return (
            <nav>
                <Link href="/">Home</Link> |&nbsp;
                <Link href="/signup">Sign up</Link> |&nbsp;
                <Link href="/signin">Sign in</Link>
            </nav>
        )
    }
    

☝ Click on the icons to view the contents of each file.

Home page

There's nothing too special about the Home page. We just create a Home() component with some HTML wrapped inside a <main></main> tag.

/app/page.jsx
export default function Home() {
  return (
    <main>
      <h1>Pro Jokes</h1>

      <hr />

      <div>
        <p>Q: What do you call a fake noodle?</p>
        <p>A: An impasta.</p>
      </div>

      <hr />

      <div>
        <p>Q: Why do bees have sticky hair?</p>
        <p>A: Because they use a honeycomb.</p>
      </div>

      <hr />

      <div>
        <p>Q: Why did the scarecrow get promoted?</p>
        <p>A: He was outstanding in his field.</p>
      </div>

    </main>
  )
}

At the moment, our jokes are visible to everyone who visits this page, but later on we'll gate some of this content.

Sign up page

The sign up page is also quite simple..

/app/signup/page.jsx
export default function SignUp() {
  return (
    <main>
      <h1>Sign up</h1>

      <form id="signup_form">

        <div>
          <label htmlFor="signup_full_name">Full Name</label>
          <input type="text" id="signup_email" required />
        </div>

        <div>
          <label htmlFor="signup_email">Email</label>
          <input type="email" id="signup_email" required />
        </div>

        <div>
          <label htmlFor="signup_password">Password</label>
          <input type="password" id="signup_password" required />
        </div>

        <div>
          <label htmlFor="signup_confirm_password">Confirm password</label>
          <input type="password" id="signup_confirm_password" required />
        </div>

        <button type="submit">Sign up</button>

      </form>

      <button>Sign up with Google</button>

    </main>
  )
}

Good to know

  • We put required attributes on all the <input> controls so that the user's browser will complain if the they leave any of these fields empty. However, this validation is only done on the client (their browser), so a savvy user could bypass this and submit empty data. We'll need to validate things again, server side.
  • <button type="submit"> is preferred over <input type="submit" /> (although both will work). Also, it's not necessary to include type="submit", but we include it because it makes the code more clear.

Sign in page

The sign in page is very similar to the sign up page..

/app/signin/page.jsx
export default function SignIn() {
  return (
    <main>
      <h1>Sign in</h1>

      <form id="signin_form">

        <div>
          <label htmlFor="signin_email">Email</label>
          <input type="email" id="signin_email" required />
        </div>

        <div>
          <label htmlFor="signin_password">Password</label>
          <input type="password" id="signin_password" required />
        </div>

        <button type="submit">Sign in</button>

      </form>

      <button>Sign in with Google</button>

    </main>
  )
}

Finally, we implement the Navbar. First, let's have a look at /app/layout.jsx.

/app/layout.jsx
import Navbar from "./Navbar";

export default function RootLayout({ children }) {
  return (
    <html lang="en">
      <head />
      <body>
        <Navbar/>
        {children}
        </body>
    </html>
  )
}

The Root Layout is like a top-level component for our whole site. Stick something in here and it will appear on every page. In our case, we want the Navbar to appear on every page, just after the opening <body> tag.

Then we implement /app/Navbar.jsx with some basic HTML and Next.js <Link>s.

/app/Navbar.jsx
import Link from "next/link";


export default function Navbar() {
    return (
        <nav>
            <Link href="/">Home</Link> |&nbsp;
            <Link href="/signup">Sign up</Link> |&nbsp;
            <Link href="/signin">Sign in</Link>
        </nav>
    )
}

&nbsp;

&nbsp; is the HTML entity for "non-breaking space". It's a handy way to generate whitespace that will render to the screen at the end of a line of HTML code.

With &nbsp;

<Link href="/">Home</Link> |&nbsp;
<Link href="/signup">Sign up</Link> |&nbsp;
<Link href="/signin">Sign in</Link>

Home | Sign up | Sign in

With whitespace

<Link href="/">Home</Link> | 
<Link href="/signup">Sign up</Link> | 
<Link href="/signin">Sign in</Link>

Home |Sign up |Sign in