What we did up to now is pretty cool!

In this lesson we’ll add a navigation bar to the page, and we’ll also add some styling to make the app look nicer.

First, I’m going to add a logo image in public/img/logo.png. It reminds the Airbnb logo, just upside down and with a different color.

Feel free to use any image you want.

I’m going to include this image in the header, which will be present in every page.

Let’s create a new file in the components directory, called Layout.js.

In there, we’ll create the shell of our application: we’ll include it in every page component to provide common UI, including basic CSS and the heading.

In this component we take the props, and we render the content props in a main tag:

components/Layout.js

const Layout = props => {
  return (
    <div>
      <main>{props.content}</main>
    </div>
  )
}

export default Layout

Then in the pages/index.js and pages/houses/[id].js we import this Layout component, and we return that component, passing the JSX as its content prop:

pages/index.js

//...
import Layout from '../components/Layout'

const content = (
  <div>
    <h2>Places to stay</h2>

    { /* all the rest of the JSX that we had in `pages/index.js` */}
  </div>
)

const Index = () => <Layout content={content} />

export default Index

See? We have wrapped our JSX in a content variable, and we pass that to the Layout component content prop, so we can access it in components/Layout.js.

Now we can do the same for the other page component we have, pages/houses/[id].js. In there, we do things a little differently: instead of creating a content variable, we directly put the component JSX inside the content prop:

pages/houses/[id].js

//...
import Layout from '../../components/Layout'

const House = props => (
  <Layout
    content={
      <div>
        <Head>
          <title>{props.house.title}</title>
        </Head>
        <img src={props.house.picture} width='100%' alt='House picture' />
        <p>
          {props.house.type} - {props.house.town}
        </p>
        <p>{props.house.title}</p>
        <p>
          {props.house.rating} ({props.house.reviewsCount})
        </p>
      </div>
    }
  />
)
//...

Why? Because in this component JSX we access the props values, so we can’t define the JSX outside of the component. I could have also written

pages/houses/[id].js

const House = props => {
	const content = (
		<div>
			<Head>
				<title>{props.house.title}</title>
			</Head>
			<img src={props.house.picture} width='100%' alt='House picture' />
			<p>
				{props.house.type} - {props.house.town}
			</p>
			<p>{props.house.title}</p>
			<p>
				{props.house.rating} ({props.house.reviewsCount})
			</p>
		</div>
	)

	return (
  	<Layout
    	content={content} />
	)
}

but it’s mostly the same, and I think a little bit more complicated to grasp at a first look.

Cool! So now we have both pages use the Layout component as their base.

We can now go back to it, and we add a little bit of CSS, using styled-jsx:

First we add a global CSS to style the body tag:

components/Layout.js

const Layout = props => {
  return (
    <div>
      <main>{props.content}</main>

      <style jsx global>{`
        body {
          margin: 0;
          font-family: Roboto, -apple-system, BlinkMacSystemFont, Segoe UI,
            Oxygen, Ubuntu, Cantarell, Fira Sans, Droid Sans, Helvetica Neue,
            sans-serif;
          font-size: 14px;
          line-height: 1.5;
          color: #333;
        }
      `}</style>
    </div>
  )
}

Then I also add some scoped CSS to style the main tag:

components/Layout.js

const Layout = props => {
  return (
    <div>
      <main>{props.content}</main>

      <style jsx global>{`
        body {
          margin: 0;
          font-family: Roboto, -apple-system, BlinkMacSystemFont, Segoe UI,
            Oxygen, Ubuntu, Cantarell, Fira Sans, Droid Sans, Helvetica Neue,
            sans-serif;
          font-size: 14px;
          line-height: 1.5;
          color: #333;
        }
      `}</style>

      <style jsx>{`
        main {
          position: relative;
          max-width: 56em;
          background-color: white;
          padding: 2em;
          margin: 0 auto;
          box-sizing: border-box;
        }
      `}</style>
    </div>
  )
}

Now, I’m going to add a header to the page. I’ll do that in a separate component, which I call Header.js, and I place it into the components folder.

Here’s a start, we include the logo and a first nav container for a couple links we’re going to add later:

components/Header.js

const Header = () => (
  <div className='nav-container'>
		<img src='/img/logo.png' alt='' />

    <nav>
    </nav>

    <style jsx>{`
      .nav-container {
        border-bottom: 1px solid #eee;
        height: 50px;
      }

      img {
        float: left;
      }
    `}</style>
  </div>
)

export default Header

Now let’s add those links I was talking about. I add two links, one is Sign up and the other is Log in. We’ll use them soon. I also make the logo link to the home page. I also add some CSS to style them nicely:

components/Header.js

import Link from 'next/link'

const Header = () => (
  <div className='nav-container'>
    <Link href='/'>
      <a>
        <img src='/img/logo.png' alt='' />
      </a>
    </Link>

    <nav>
      <ul>
        <li>
          <Link href='/register'>
            <a>Sign up</a>
          </Link>
        </li>
        <li>
          <Link href='/login'>
            <a>Log in</a>
          </Link>
        </li>
      </ul>
    </nav>

    <style jsx>{`
      ul {
        margin: 0;
        padding: 0;
      }

      li {
        display: block;
        float: left;
      }

      a {
        text-decoration: none;
        display: block;
        margin-right: 15px;
        color: #333;
      }

      nav a {
        padding: 1em 0.5em;
      }

      .nav-container {
        border-bottom: 1px solid #eee;
        height: 50px;
      }

      img {
        float: left;
      }

      ul {
        float: right;
      }
    `}</style>
  </div>
)

export default Header

Now in Layout.js, add

import Header from './Header'

and inside the JSX:

const Layout = props => {
  return (
    <div>
      <Header />
      <main>{props.content}</main>
      ...

Awesome! This should be the end result so far:

The code for this lesson is available at https://github.com/flaviocopes/airbnb-clone-react-nextjs/commit/042e665f9c50d4f12e2d45ce769246a735feeb01


Go to the next module