How to set the next/image component to 100% height
nextjs-supabase

How to set the next/image component to 100% height

If your <Image / component ignores height: 100% and appears too small or misaligned, the issue is almost always that the parent container lacks an explicit

2026-06-14
7 min read
How to set the next/image component to 100% height

TL;DR#

If your <Image /> component ignores height: 100% and appears too small or misaligned, the issue is almost always that the parent container lacks an explicit height, or you're using layout="responsive" (the default) instead of layout="fill".

The fix is: set fill on the Image, ensure the parent has position: relative and a concrete height, and avoid setting height directly on the Image tag.

If that doesn't work, check whether your parent is inside a flex or grid container — those require align-items: stretch or height: 100% on the flex/grid item itself.

What you'll see#

You write this in your component:

tsx
// app/page.tsx
import Image from 'next/image';

export default function Hero() {
  return (
    <div className="h-[500px]">
      <Image
        src="/hero.jpg"
        alt="Hero"
        className="h-full w-full object-cover"
      />
    </div>
  );
}

But the image renders at its natural height — say, 300px — instead of filling the 500px parent. You see a gap below it, and DevTools shows the <img> element has height: auto and no explicit height set.

I ran into this exact behavior on a client project last year, and I've watched it trip up teammates on at least three other codebases since. The code looks correct, the parent clearly has a height, and yet the image stubbornly renders at its intrinsic size.

This happens when you use <Image> without layout="fill" or fill, especially when trying to make it responsive inside a fixed-height container. The behavior is identical in development and production — it's not a hydration or build-time quirk. (If you're seeing Error: Hydration failed instead, see our hydration mismatch fix guide.)

It reproduces across all browsers because it's not a rendering bug — it's how Next.js enforces layout stability and prevents Cumulative Layout Shift (CLS).

Root cause#

Next.js Image components default to layout="intrinsic" via the layout prop, which preserves the image's natural aspect ratio and sets height: auto to avoid CLS (Cumulative Layout Shift) — a Core Web Vital that measures unexpected layout movement. In this mode, the CSS height property set via height: 100% on the <img> tag has no effect because the parent <div> has no explicit height — and even if it does, the image itself is constrained by max-width: 100% and height: auto.

Next.js explicitly sets height: auto on the rendered <img> when using intrinsic layout — overriding any className="h-full" you add. If you want 100% height, you must switch to the fill prop, which changes the rendering strategy entirely.

The fix#

Here's the minimal working pattern:

tsx
// app/page.tsx
import Image from 'next/image';

export default function Hero() {
  return (
    <div className="relative h-[500px] w-full">
      <Image
        src="/hero.jpg"
        alt="Hero"
        fill
        className="object-cover"
      />
    </div>
  );
}

That single change — adding the fill prop — addresses the cause because fill tells Next.js to render the image as a <span> wrapper with position: absolute, and the <img> inside it uses position: absolute; inset: 0; object-fit: cover (or contain). This bypasses the height: auto constraint and lets the image stretch to fill its positioned parent. Proper parent container sizing — an explicit height on the positioned parent — is what makes this work.

I've shipped this exact pattern on production hero banners, marketing pages, and dashboard headers. Once you internalize the "positioned parent + fill" mental model, the rest clicks.

Step by step#

  1. Wrap the <Image> in a container with position: relative.
  2. Give the container an explicit height — h-[500px], h-96, or h-full (if inside a flex/grid with defined height).
  3. Add fill to <Image>.
  4. Use className="object-cover" (or object-contain) to control cropping.

That's it. No width, height, or layout props needed.

Which approach works?#

| Approach | Next.js 13+ | Recommended | |---|---|---| | className="h-full" on <Image> | ❌ Ignored (height: auto wins) | No | | layout="responsive" | ⚠️ Deprecated | No | | fill + position: relative parent | ✅ Works | Yes |

Verify the fix#

Run npm run dev, open the page in your browser, and inspect the image with DevTools.

You should see:

  • The parent <div> has height: 500px.
  • The <Image> renders as a <span> with position: relative, display: block, and width: 100%; height: 100%.
  • The inner <img> has position: absolute; inset: 0; object-fit: cover.

Run this in the console to confirm:

js
// In Chrome DevTools Console:
document.querySelector('div').offsetHeight

You should see 500.

When I'm debugging this on client projects, the console snippet above is the first thing I check — if the parent doesn't report the expected height, no Image configuration will save you.

If you still see the image at 300px height, check for two common variants.

Variant A — Parent height depends on siblings#

If your container is inside a flex container (e.g., flex flex-col) and you set h-full on the parent, but the flex container itself has no height, the image won't grow.

Fix: Set flex-1 on the parent container, or give the flex container min-height: 100vh.

tsx
<div className="flex flex-col h-screen">
  <div className="flex-1 relative">
    <Image src="/hero.jpg" alt="Hero" fill className="object-cover" />
  </div>
</div>

Variant B — Using layout="responsive" incorrectly#

Some older guides suggest layout="responsive" — but this was deprecated in Next.js 13+ in favor of the fill prop. If you see layout="responsive" in your code, replace it with fill.

tsx
<>
  {/* ❌ Deprecated (Next.js <13 only) */}
  <Image src="/hero.jpg" layout="responsive" className="h-full w-full" />

  {/* ✅ Correct (Next.js 13+) */}
  <Image src="/hero.jpg" fill className="object-cover" />
</>

Why this happens (and how to avoid it next time)#

Next.js enforces strict layout rules to meet Core Web Vitals — especially CLS. The intrinsic layout mode is safe by default: it prevents overflow and ensures images never exceed their natural size. But it assumes you want the image's aspect ratio, not its full height. This assumption conflicts with many responsive design patterns that rely on height: 100% to make images fill their containers across breakpoints — which is why the fill prop exists.

To prevent regressions, add a simple ESLint rule in your project:

json
{
  "rules": {
    "@next/next/no-img-element": "error",
    "jsx-a11y/alt-text": "error"
  }
}

And write a unit test with Jest + Testing Library to catch layout mismatches early:

tsx
// __tests__/HeroImage.test.tsx
import { render, screen } from '@testing-library/react';
import Hero from '@/app/page';

test('renders Image with fill and correct parent', () => {
  render(<Hero />);
  const image = screen.getByAltText('Hero');
  expect(image.parentElement).toHaveClass('relative');
  expect(image.parentElement).toHaveStyle('height: 500px');
});

For a full project structure that makes these tests easier to maintain, see How to Structure Your Next.js App Router Project for Scale.

Finally, remember: fill only works when the parent has a defined height — either explicit (pixels, vh, rem) or implicit (flex/grid with flex: 1, grid-template-rows, or height: 100%). If the parent height is auto, the image will collapse to 0px.

FAQ#

Why does height: 100% not work on <Image>?#

Because Next.js sets height: auto on the rendered <img> by default. CSS height: 100% requires the parent to have a non-auto height — and even then, height: auto on the child overrides it.

Can I use width="100%" height="100%" instead of fill?#

No — width and height props on <Image> are for intrinsic layout and must be numeric pixels. Using "100%" is invalid and ignored.

How do I make the image responsive and full-height?#

In responsive design workflows, use fill with object-cover. The image will scale to fill the container's width and height, cropping as needed — this is standard for hero banners and adapts cleanly to any viewport size.

Does fill cause layout shifts?#

No — fill renders the image with position: absolute and inset: 0, so it doesn't affect document flow. CLS risk is low if you provide a placeholder or blur-up.

Written by

Mahdi Br
Mahdi Br

Full-Stack Dev — Next.js & Supabase

Solo developer building SaaS products with Next.js and Supabase. Writing about production patterns the official docs skip.

Remote

One email a month — no fluff

RLS gotchas, Next.js cache debugging, and the one Supabase setting that bit me last month.