payloadcms / payloadcms/payload
Sizes attribute in ImageMedia uses w instead of px - causes browser to ignore all breakpoint hints
@paulpopus is already working on this.
Since Jun 3, 2026.
- Dominant language
- TypeScript
- Stars
- 44.8k
- Forks
- 4.2k
- Avg merge
- 2d 21h
- Merged PRs (30d)
- 53
Description
Describe the Bug
Hey! Found a bug in the ImageMedia component that affects both templates/website and templates/with-vercel-website.
- https://github.com/payloadcms/payload/blob/main/templates/website/src/components/Media/ImageMedia/index.tsx
- https://github.com/payloadcms/payload/blob/main/templates/with-vercel-website/src/components/Media/ImageMedia/index.tsx
The default sizes string is built like this:
Object.entries(breakpoints)
.map(([, value]) => `(max-width: ${value}px) ${value * 2}w`)
.join(', ')
The problem is the w unit, that's a srcset width descriptor and is only valid inside srcset, not sizes. The sizes attribute expects CSS length units like px, vw, em, etc. (MDN
(https://developer.mozilla.org/en-US/docs/Web/API/HTMLImageElement/sizes), HTML spec (https://html.spec.whatwg.org/multipage/images.html)).
Browsers silently discard the invalid values and fall back to 100vw, so the entire breakpoint calculation does nothing in practice. Since Next.js relies on sizes to decide which srcset entry to fetch, all
images end up downloading a full-viewport-width variant regardless of their actual layout size.
The fix is straightforward, use px and drop the * 2 (Next.js handles retina/DPR automatically via srcset, so doubling the hint works against you):
Object.entries(breakpoints)
.map(([, value]) => `(max-width: ${value}px) ${value}px`)
.join(', ')
Interestingly, the ecommerce template already does this correctly in templates/ecommerce/src/components/Media/Image/index.tsx, so it's just the two website templates that have the bug.
Link to the code that reproduces this issue
pnpx create-payload-app@latest -t website
Reproduction Steps
https://github.com/payloadcms/payload
Just run pnpx create-payload-app@latest -t website and observe issue in src/components/Media/ImageMedia/index.tsx
Which area(s) are affected?
area: templates
Environment Info
Binaries:
Node: 25.0.0
npm: 11.6.2
Yarn: N/A
pnpm: 10.28.2
Relevant Packages:
payload: 3.84.1
next: 16.2.6
@payloadcms/db-vercel-postgres: 3.84.1
@payloadcms/drizzle: 3.84.1
@payloadcms/graphql: 3.84.1
@payloadcms/live-preview: 3.84.1
@payloadcms/live-preview-react: 3.84.1
@payloadcms/next/utilities: 3.84.1
@payloadcms/plugin-cloud-storage: 3.84.1
@payloadcms/plugin-form-builder: 3.84.1
@payloadcms/plugin-nested-docs: 3.84.1
@payloadcms/plugin-redirects: 3.84.1
@payloadcms/plugin-search: 3.84.1
@payloadcms/plugin-seo: 3.84.1
@payloadcms/richtext-lexical: 3.84.1
@payloadcms/storage-vercel-blob: 3.84.1
@payloadcms/translations: 3.84.1
@payloadcms/ui/shared: 3.84.1
react: 19.2.1
react-dom: 19.2.1
Operating System:
Platform: linux
Arch: x64
Version: #1 SMP PREEMPT_DYNAMIC Fri, 01 May 2026 15:49:22 +0000
Available memory (MB): 31724
Available CPU cores: 12
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Assessment
This issue has not been assessed yet.