Next.js Components and Layout
In React and Next.js, components are the core of building user interfaces. By breaking UI into independent, reusable parts, we can more efficiently develop and maintain complex applications. This chapter explores how to organize components in Next.js and create shared layouts for multiple pages.
1. Component Basics
In Next.js, components are written exactly the same way as in standard React projects. Typically, we store all components in a components folder in the project root directory for easy management.
Creating a Simple Component
Let's create a simple Button component.
Create file:
components/Button.jsWrite component code:
jsx// components/Button.js import styles from './Button.module.css'; export default function Button({ children, onClick }) { return ( <button className={styles.button} onClick={onClick}> {children} </button> ); }Add styles for the component (optional):
components/Button.module.csscss.button { background-color: #0070f3; color: white; padding: 10px 20px; border: none; border-radius: 5px; cursor: pointer; font-size: 1rem; } .button:hover { background-color: #005bb5; }
Using Components in Pages
Now you can import and use this Button component in any page.
// pages/index.js
import Button from '../components/Button';
export default function HomePage() {
const handleClick = () => {
alert('Button clicked!');
};
return (
<div>
<h1>Welcome to My App</h1>
<Button onClick={handleClick}>Click Me</Button>
</div>
);
}2. Page Layouts
In most websites, multiple pages share the same structure, such as header, footer, and navigation bar. In Next.js, there are several ways to implement this shared layout.
Method 1: Create a Layout Component
The most common approach is to create a Layout component and use it to wrap each page's content.
Create
Layoutcomponent:components/Layout.jsThis component typically contains the header, footer, and renders page content through the
childrenprop.jsx// components/Layout.js import Head from 'next/head'; import Header from './Header'; import Footer from './Footer'; export default function Layout({ children, title = 'My Next.js App' }) { return ( <div> <Head> <title>{title}</title> <meta charSet="utf-8" /> <meta name="viewport" content="initial-scale=1.0, width=device-width" /> </Head> <Header /> <main>{children}</main> <Footer /> </div> ); }We also need to create
HeaderandFootercomponents.components/Header.jsjsximport Link from 'next/link'; import styles from './Header.module.css'; export default function Header() { return ( <header className={styles.header}> <nav> <Link href="/">Home</Link> <Link href="/about">About</Link> <Link href="/contact">Contact</Link> </nav> </header> ); }components/Footer.jsjsximport styles from './Footer.module.css'; export default function Footer() { return ( <footer className={styles.footer}> <p>© {new Date().getFullYear()} My Awesome App. All rights reserved.</p> </footer> ); }Use
Layoutcomponent in_app.jsTo have all pages use this layout, we can wrap
Componentinpages/_app.js.jsx// pages/_app.js import Layout from '../components/Layout'; import '../styles/globals.css'; function MyApp({ Component, pageProps }) { return ( <Layout> <Component {...pageProps} /> </Layout> ); } export default MyApp;This way, the
Layoutcomponent will automatically apply to all pages without needing to import it separately in each page file.
Method 2: Per-Page Layouts
Sometimes, your application may need multiple different layouts (e.g., one for the main app, one for the admin dashboard). In this case, you can add a getLayout property to page components.
Modify
_app.jsFirst, modify
_app.jsto support thegetLayoutfunction.jsx// pages/_app.js import '../styles/globals.css'; export default function MyApp({ Component, pageProps }) { // Use getLayout if the page has one const getLayout = Component.getLayout || ((page) => page); return getLayout(<Component {...pageProps} />); }Specify layout in pages
Now you can define
getLayoutin pages that need a specific layout.jsx// pages/dashboard.js import AdminLayout from '../components/AdminLayout'; export default function DashboardPage() { return ( <div> <h1>Admin Dashboard</h1> {/* ... */} </div> ); } // Define the layout for this page DashboardPage.getLayout = function getLayout(page) { return <AdminLayout>{page}</AdminLayout>; };Pages that don't need a special layout will default to no layout, or you can provide a default layout.
3. Layouts in App Router (Next.js 13+)
In the App Router introduced in Next.js 13, layout management becomes more native and powerful.
layout.jsfile: You can create alayout.jsfile in any route segment to define shared UI. This layout applies to that route segment and all its child routes.
Example: app/dashboard/layout.js
// app/dashboard/layout.js
export default function DashboardLayout({ children }) {
return (
<section>
{/* Shared dashboard navigation */}
<nav>Dashboard Nav</nav>
{children}
</section>
);
}This layout will automatically wrap app/dashboard/page.js and all child pages like app/dashboard/settings/page.js.
Summary
- Components are the basic units for building UI and should be kept independent and reusable.
- Shared layouts can be implemented by creating a
Layoutcomponent and using it in_app.js. - For complex applications requiring multiple layouts, the per-page layout pattern provides greater flexibility.
- In the App Router, layouts are managed in a more structured way through
layout.jsfiles.
In the final chapter, we'll provide some useful learning resources to help you continue your in-depth study of Next.js.