The Tool Desk
Outbyte PC Repair FREEClear out junk files and repair common Windows errorsFree Scan →Outbyte Driver Updater FREEScan for outdated or missing drivers - takes under a minuteDriver Scan →Some links on this page are affiliate links: if you buy through them we may earn a commission, at no extra cost to you.
A Next.js image gallery is application UI that you assemble from a layout, interaction state, and the framework’s next/image component. Next.js does not provide a complete gallery widget or dedicated gallery API. The Image component extends HTML <img> for automatic image optimization, while your code decides the grid, crop behavior, lightbox, filtering, keyboard controls, and pagination. The most important implementation details are matching image geometry to your CSS and passing an accurate sizes value.
What you are building
Think of the gallery as two layers:
- Gallery UI: React data, CSS Grid or Flexbox, selection state, overlays, navigation, and any accessibility behavior.
- Image delivery:
next/imagehandles responsive variants, optimization, intrinsic dimensions, lazy loading, and remote-source validation.
The official Image Component reference includes a grid-style example, but it does not establish an official lightbox, filtering, keyboard-navigation, or pagination recipe. Those behaviors require your own components or a separately evaluated library.
Choose image geometry: dimensions or fill
Use width and height when source dimensions are known
For static assets or records that include reliable intrinsic dimensions, provide both props. They describe the source ratio and let the browser reserve space before the file arrives, reducing layout shift. CSS can still make the rendered width responsive while the ratio remains natural.
import Image from 'next/image';
export function PhotoCard({ photo }) {
return (
<article className="card">
<Image
src={photo.src}
alt={photo.alt}
width={photo.width}
height={photo.height}
sizes="(min-width: 1200px) 25vw, (min-width: 700px) 33vw, 50vw"
/>
<h3>{photo.title}</h3>
</article>
);
}
Set the CSS width to 100% when the card controls the horizontal size, and keep height: auto unless you intentionally want a fixed crop.
#1 Best Overall
Use fill when the container controls the tile
fill makes the image occupy a positioned parent. This is useful for uniform cards where every cell has the same aspect ratio. The parent must have a non-static position and a defined height or aspect ratio. Choose objectFit: 'cover' for edge-to-edge tiles that crop, or 'contain' when the entire image must remain visible with possible empty space.
import Image from 'next/image';
export function Tile({ photo }) {
return (
<article className="tile">
<Image
src={photo.src}
alt={photo.alt}
fill
sizes="(min-width: 1200px) 25vw, (min-width: 700px) 33vw, 50vw"
style={{ objectFit: 'cover' }}
/>
</article>
);
}
.tile {
position: relative;
aspect-ratio: 4 / 3;
overflow: hidden;
}
.tile img { display: block; }
Make sizes match the real grid
For responsive CSS or fill images, sizes tells the browser how wide the image will render at each viewport. Next.js uses that information to generate a width-based srcset. If you omit it, the browser assumes 100vw, which can download unnecessarily large files.
Derive the expression from your columns, gaps, and max-width. A four-column grid inside a full-width container is approximately 25vw per tile; at medium widths with three columns it is about 33vw. If the gallery has a 1,100px max-width, include that constraint rather than claiming the tile is always a quarter of the viewport:
Quick wins for a faster PC:
Fix the driver behind crashes, sound loss and screen glitchesFind Drivers →Clear out junk files and repair common Windows errorsFree Scan →Scan for outdated or missing drivers - takes under a minuteDriver Scan →sizes="(min-width: 1200px) 275px, (min-width: 900px) 33vw, (min-width: 600px) 50vw, 100vw"
Account for gaps when precision matters. For example, two columns with a 16px gap in a 700px container render each tile at roughly half the container minus 8px. You can use a CSS calc() expression in sizes where supported, or choose a conservative fraction that does not understate the rendered width. Revisit the string whenever breakpoints or container widths change.
Rank #2
- HTML CSS Design and Build Web Sites
- Comes with secure packaging
- It can be a gift option
A complete responsive gallery
The following App Router example keeps gallery data separate from presentation and uses a uniform crop. Replace the placeholder records with your database or CMS response.
// app/gallery/Gallery.jsx
import Image from 'next/image';
import styles from './gallery.module.css';
export default function Gallery({ photos }) {
return (
<section className={styles.grid} aria-label="Photo gallery">
{photos.map((photo) => (
<figure className={styles.tile} key={photo.id}>
<Image
src={photo.src}
alt={photo.alt}
fill
sizes="(min-width: 1200px) 25vw, (min-width: 700px) 33vw, 50vw"
style={{ objectFit: 'cover' }}
/>
<figcaption>{photo.title}</figcaption>
</figure>
))}
</section>
);
}
/* app/gallery/gallery.module.css */
.grid {
display: grid;
grid-template-columns: repeat(2, minmax(0, 1fr));
gap: 1rem;
max-width: 1200px;
margin-inline: auto;
}
.tile {
position: relative;
aspect-ratio: 4 / 3;
overflow: hidden;
margin: 0;
}
@media (min-width: 700px) {
.grid { grid-template-columns: repeat(3, minmax(0, 1fr)); }
}
@media (min-width: 1200px) {
.grid { grid-template-columns: repeat(4, minmax(0, 1fr)); }
}
Use meaningful alternative text. If a tile is purely decorative, use an empty alt rather than repeating a nearby caption. A clickable tile should be a real link or button, not a click handler on a generic div.
Allow remote sources narrowly
Runtime URLs must be authorized in next.config.js. Prefer images.remotePatterns, specifying protocol, host, pathname, and query restrictions that match your provider. Omitted fields imply wildcards, so leaving fields out can admit more URLs than intended. The older domains option lacks protocol, port, and pathname controls and has been deprecated in favor of remotePatterns since Next.js 14.
Free tools Windows power users keep installed
One-click scans. No signup required.
// next.config.js
/** @type {import('next').NextConfig} */
const nextConfig = {
images: {
remotePatterns: [
{
protocol: 'https',
hostname: 'images.example-cdn.com',
port: '',
pathname: '/gallery/**',
search: '',
},
],
},
};
module.exports = nextConfig;
Restart the development server after changing configuration. If your provider uses signed query parameters, configure the permitted search pattern according to your installed Next.js version rather than copying a wildcard blindly. Never let arbitrary user-supplied hosts become image URLs without validation.
Rank #3
Local, remote, and CMS data decisions
| Choice | Best fit | Implementation concern |
|---|---|---|
| Static import | Build-known images in public or imported files |
Dimensions are known; no remote allowlist is needed. |
| Remote URL with dimensions | CMS records that store width and height | Allowlist the exact source and pass dimensions from trusted metadata. |
| Remote URL with fill | Unknown or variable source dimensions in fixed tiles | Position the wrapper, define its aspect ratio, and choose crop behavior. |
Loading, preload, and quality settings
Do not preload every gallery tile. The preload prop is intended for an image likely to be the page’s Largest Contentful Paint element, usually an above-the-fold hero. If the likely LCP image changes by viewport, or you use other fetch-priority settings, follow the current reference for your version instead of forcing preload. Below-the-fold gallery items should use normal loading behavior and be tuned from the page’s actual layout.
The current Image reference documents a quality range of 1–100 and a default of 75 (reference updated March 16, 2026). In the Next.js 16 version history, the configured default qualities allowlist became [75] (Pages Router reference updated February 27, 2026). If you request another quality value, check your project’s next.config.js and installed version; configure allowed values explicitly where required.
The current reference marks onLoadingComplete deprecated. Avoid building new code around it; use the loading and layout APIs documented for your release.
Interactions you must implement yourself
Lightbox or detail view
Store the selected photo ID in React state, render an accessible dialog, label it, and provide a visible close button. Locking background scroll, restoring focus, and handling Escape are application responsibilities.
Rank #4
- Brand: Wiley
- Set of 2 Volumes
- A handy two-book set that uniquely combines related technologies Highly visual format and accessible language makes these books highly effective learning tools Perfect for beginning web designers and front-end developers
Filtering and sorting
Filter the data before mapping it to tiles. Keep filter controls as labeled form elements and expose the result count to assistive technology when it changes.
Keyboard navigation
Use links or buttons for tiles, preserve a logical tab order, and ensure dialog controls are reachable without a pointer. The Image component does not add gallery-level arrow-key behavior.
Pagination and large collections
Paginate or virtualize the data set when rendering thousands of records. Keep stable keys, provide a loading state, and ensure newly loaded content is announced or naturally reachable. Lazy image loading reduces network work but does not replace a data-loading strategy.
What’s actually slowing this PC down?
Pick the symptom - the matching free tool is one click away.
Troubleshooting
- “Invalid src prop” or an unconfigured host: the URL does not match a
remotePatternsentry. Verify protocol, hostname, pathname, port, and query string, then restart Next.js. - Images are much larger than expected: inspect the rendered width at each breakpoint and add or correct
sizes. Without it, the browser assumes100vw. - Fill image has no size or overlaps content: the parent is not positioned or has no height. Add
position: relativeand an explicit height oraspect-ratio. - Unexpected cropping:
coverintentionally trims edges. Usecontainor the dimensions approach when the full image must be visible. - Layout jumps while loading: provide accurate
width/height, or reserve space with the fill wrapper’s aspect ratio. - Quality value rejected after upgrading: compare the requested
qualitywith the configured allowlist and your Next.js version, especially Next.js 16. - Remote image returns an error: confirm the URL is publicly fetchable, uses the allowed protocol, and does not require browser-only authentication or expiring credentials that have already lapsed.
Performance and reliability checklist
- Measure the actual rendered tile width at each breakpoint and encode it in
sizes. - Use
width/heightfor known ratios; usefillonly with a deliberate container geometry. - Keep remote patterns specific to the CDN path your application owns.
- Reserve preload for a stable, above-the-fold LCP image.
- Do not equate lazy loading with pagination; large data sets still need a rendering strategy.
- Recheck the installed Next.js documentation after upgrades because props and configuration behavior can change.
Or skip the browser setup
If your gallery pipeline also needs server-side screenshots of pages, ScreenshotNeo provides a single website screenshot API call instead of maintaining browser automation. It accepts cookie and consent banners before capture and removes more than 60 known consent platforms, newsletter popups, and chat widgets; each step can be disabled. Bot checks, CAPTCHAs, blank pages, timeouts, failed loads, and cache hits cost nothing, and response headers identify the page verdict and whether it was billed. Its MCP server exposes take_screenshot, get_page_info, and capture_pdf for Claude, Cursor, and other MCP clients.
Here is a complete request (see the ScreenshotNeo API documentation for all options):
Best Value
curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://stripe.com -o shot.webp
You can also use Python:
import requests
r = requests.get("https://api.screenshotneo.com/v1/shot", params={"access_key": "YOUR_API_KEY", "url": "https://stripe.com"}, timeout=90)
open("shot.webp", "wb").write(r.content)
Or Node.js:
const q = new URLSearchParams({ access_key: 'YOUR_API_KEY', url: 'https://stripe.com' });
const res = await fetch(`https://api.screenshotneo.com/v1/shot?${q}`);
Every feature is included on every plan. The Free plan includes 1,000 shots per month with no card; paid plans start at $5 for 3,000 shots. Create a free ScreenshotNeo account to get the API key.
FAQ
Does Next.js include a gallery component?
No. It includes the optimized Image component; grid and interaction behavior are yours to build.
Should every tile use fill?
No. Use intrinsic dimensions when the source ratio is known; reserve fill for container-controlled geometry.
Why does my remote image work in a normal img tag but not with Image?
Next.js validates remote URLs against remotePatterns; a normal img tag does not perform that framework check.
Frequently Asked Questions
Can I build a masonry gallery with next/image?
Yes. Use a masonry layout implemented with CSS or a library, then apply the same width/fill and sizes rules to each image. The layout engine is separate from next/image.
Is objectFit required with fill?
No, but setting it explicitly makes the intended crop or containment behavior clear. Use cover for uniform cropped tiles and contain when the whole image must remain visible.
Do these 3 things before closing this tab:
1Scan for outdated or missing drivers - takes under a minute2Clear out junk files and repair common Windows errors3Fix the driver behind crashes, sound loss and screen glitchesThe Bottom Line
Build the gallery UI yourself, make cell geometry explicit, match sizes to the real breakpoints, and keep remote image permissions narrow. That combination gives next/image enough information to optimize downloads without pretending it is a complete gallery product.
Quick Recap
Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.

