Next.js Components
Building blocks of your Next.js application
What are Components in Next.js?
Next.js components are React components with additional features for optimization, routing, and data fetching.
Next.js enhances React components with: Server Components, automatic code splitting, built-in optimization for images/fonts, and more.
Component Categories
Server Components
Default in Next.js App Router
- Render on the server
- Zero JavaScript to client
- Can access backend resources
- Improved performance
Client Components
Use 'use client' directive
- Interactive features
- Use React hooks
- Browser APIs access
- Event listeners
Server vs Client Components
Server Component (Default)
// app/components/UserProfile.tsx
// This is a Server Component by default
async function UserProfile({ userId }: { userId: string }) {
// Can directly fetch data on server
const user = await fetch(`https://api.example.com/users/${userId}`)
.then(res => res.json())
return (
<div>
<h2>{user.name}</h2>
<p>{user.email}</p>
</div>
)
}
export default UserProfile
Client Component
'use client' // This directive makes it a Client Component
import { useState } from 'react'
export default function Counter() {
const [count, setCount] = useState(0)
return (
<div>
<p>Count: {count}</p>
<button onClick={() => setCount(count + 1)}>
Increment
</button>
</div>
)
}
When to Use Each
| Use Case | Server Component | Client Component |
|---|---|---|
| Fetch data | ✅ | ❌ |
| Access backend resources | ✅ | ❌ |
| Use React hooks (useState, useEffect) | ❌ | ✅ |
| Event listeners (onClick, onChange) | ❌ | ✅ |
| Browser APIs (localStorage, etc.) | ❌ | ✅ |
| Keep sensitive data on server | ✅ | ❌ |
Best Practice: Use Server Components by default, and only use Client Components when you need interactivity.
Next.js Image Component
The Image component extends the HTML <img> element with automatic optimization.
Basic Usage
import Image from 'next/image'
export default function Avatar() {
return (
<Image
src="/profile.jpg"
alt="Profile picture"
width={500}
height={500}
/>
)
}
Remote Images
import Image from 'next/image'
export default function RemoteImage() {
return (
<Image
src="https://example.com/photo.jpg"
alt="Remote photo"
width={800}
height={600}
priority // Load image with high priority
/>
)
}
// next.config.js - Configure remote domains
module.exports = {
images: {
remotePatterns: [
{
protocol: 'https',
hostname: 'example.com',
},
],
},
}
Fill Container
import Image from 'next/image'
export default function BackgroundImage() {
return (
<div style={{ position: 'relative', width: '100%', height: '400px' }}>
<Image
src="/background.jpg"
alt="Background"
fill
style={{ objectFit: 'cover' }}
/>
</div>
)
}
Key Features
- Automatic Optimization: Serves modern formats (WebP, AVIF)
- Responsive: Automatically generates multiple sizes
- Lazy Loading: Images load as they enter viewport
- Blur Placeholder: Show blur-up preview while loading
- Priority Loading: Preload critical images (LCP)
Important: Always provide
width and height (or use fill) to prevent layout shift.
Next.js Link Component
The Link component enables client-side navigation between routes.
Basic Usage
import Link from 'next/link'
export default function Navigation() {
return (
<nav>
<Link href="/">Home</Link>
<Link href="/about">About</Link>
<Link href="/blog">Blog</Link>
</nav>
)
}
Dynamic Routes
import Link from 'next/link'
export default function BlogList({ posts }) {
return (
<ul>
{posts.map((post) => (
<li key={post.id}>
<Link href={`/blog/${post.slug}`}>
{post.title}
</Link>
</li>
))}
</ul>
)
}
Active Link Styling
'use client'
import Link from 'next/link'
import { usePathname } from 'next/navigation'
export default function NavLink({ href, children }) {
const pathname = usePathname()
const isActive = pathname === href
return (
<Link
href={href}
className={isActive ? 'active' : ''}
>
{children}
</Link>
)
}
Prefetching
Next.js automatically prefetches links in the viewport:
// Disable prefetching for specific links
<Link href="/heavy-page" prefetch={false}>
Heavy Page
</Link>
Performance: Link component prefetches pages in the background for instant navigation.
Next.js Script Component
The Script component optimizes loading of third-party scripts.
Loading Strategies
import Script from 'next/script'
export default function Page() {
return (
<>
{/* Load after page is interactive (default) */}
<Script
src="https://example.com/script.js"
strategy="afterInteractive"
/>
{/* Load before page is interactive */}
<Script
src="https://example.com/critical.js"
strategy="beforeInteractive"
/>
{/* Load during browser idle time */}
<Script
src="https://example.com/analytics.js"
strategy="lazyOnload"
/>
</>
)
}
Inline Scripts
import Script from 'next/script'
export default function Page() {
return (
<Script id="show-banner" strategy="lazyOnload">
{`
console.log('Page loaded!')
document.getElementById('banner').style.display = 'block'
`}
</Script>
)
}
Event Handlers
import Script from 'next/script'
export default function Page() {
return (
<Script
src="https://example.com/script.js"
onLoad={() => {
console.log('Script loaded successfully')
}}
onError={(e) => {
console.error('Script failed to load', e)
}}
/>
)
}
Font Optimization
Next.js automatically optimizes fonts to eliminate layout shift.
Google Fonts
// app/layout.tsx
import { Inter, Roboto_Mono } from 'next/font/google'
const inter = Inter({
subsets: ['latin'],
display: 'swap',
})
const robotoMono = Roboto_Mono({
subsets: ['latin'],
display: 'swap',
})
export default function RootLayout({ children }) {
return (
<html lang="en" className={inter.className}>
<body>{children}</body>
</html>
)
}
Local Fonts
import localFont from 'next/font/local'
const myFont = localFont({
src: './my-font.woff2',
display: 'swap',
})
export default function RootLayout({ children }) {
return (
<html lang="en" className={myFont.className}>
<body>{children}</body>
</html>
)
}
Multiple Weights
import { Roboto } from 'next/font/google'
const roboto = Roboto({
weight: ['400', '700'],
style: ['normal', 'italic'],
subsets: ['latin'],
display: 'swap',
})
Benefits: Fonts are self-hosted, zero layout shift, and no external network requests.