Part of #734. After #766, the API was adopted in Jahia/luxe-jahia-demo#458 and on Jahia/jahia.com: 37 of 43 call sites landed on <JImage>, luxe deleted a 452-line userland wrapper, and the URL tier is used only where an <img> cannot go. The API works. The developer experience around it does not yet, and five things should change before release.
1. The guide teaches the one layout nobody could use. It leads with layout="fill" sizes="auto", and the layout table routes "%, fr, rem, a grid cell, an aspect-ratio box" there. But fill positions the image absolutely over its parent, which is not what a normal-flow slot wants: 0 of 16 luxe sites and 9 of 13 fluid jahia.com sites could use it. Each codebase invented a different stand-in, so the same job is now written four ways. full-width + sizes="auto" already produces byte-identical src/srcSet/sizes/loading to fill + sizes="auto" — the only thing missing is a name and a paragraph for "unknown slot width, normal flow". Two slot shapes have no honest representation today and both collapse into that same case: an aspect-ratio box, and a height-constrained slot. Both currently make callers declare a slotWidth their CSS contradicts.
2. Live defect: widths without slotWidth emits sizes="(min-width: undefinedpx) undefinedpx, 100vw". Browsers discard the media query and fetch the largest candidate on every screen — the exact failure the API exists to prevent. candidateWidths' missing-slotWidth throw is skipped when widths is explicit, and derivedSizes has no equivalent guard. One if.
3. The width -> slotWidth rename is silent at compile time and fatal at render. width is still legal — it is now the HTML attribute — so every call site written against the previous API type-checks and throws on first render. Requiring width/height as a pair turns each one into a loud error at the right place. The JSDoc already says they come as a pair.
4. getImageProps is reached past by both of its users. It has no fallback, so both Island call sites hand-build a bare { src, alt } literal with no srcSet, no dimensions and no cache dependency. Its context is optional and omitting it silently drops both the cache dependency and setImageDefaults — and the guide's own Island example omits it. Give it fallback, make context required.
5. Rename ImageProps -> ImgProps while it is still free. It is the type of what comes out of getImageProps, not the component's props — which is what next/image means by ImageProps, and what JImageProps means here. The link API next door already names the same concept AnchorProps and reserves LinkProps for the wrapper object.
Also worth fixing in the guide: alt (required) is documented at line 180 and fallback not at all, though roughly a third of real call sites need it; and "a plain instance does not resize images" — the single most surprising Jahia fact — sits at line 200, well after a reader would have concluded their srcSet is broken.
Two smaller runtime issues: sizes="auto" + preload throws, but those props legitimately arrive from different layers (a shared wrapper's default and a leaf view) and the wrapper cannot express the exclusion — a development warning plus a fallback to the derived sizes is better than a 500 on a production page. And a node whose j:width extraction never ran silently loses both its CLS reservation and loading="lazy", with nothing warning and the guide never naming j:width.
Part of #734. After #766, the API was adopted in Jahia/luxe-jahia-demo#458 and on Jahia/jahia.com: 37 of 43 call sites landed on
<JImage>, luxe deleted a 452-line userland wrapper, and the URL tier is used only where an<img>cannot go. The API works. The developer experience around it does not yet, and five things should change before release.1. The guide teaches the one layout nobody could use. It leads with
layout="fill" sizes="auto", and the layout table routes "%, fr, rem, a grid cell, an aspect-ratio box" there. Butfillpositions the image absolutely over its parent, which is not what a normal-flow slot wants: 0 of 16 luxe sites and 9 of 13 fluid jahia.com sites could use it. Each codebase invented a different stand-in, so the same job is now written four ways.full-width+sizes="auto"already produces byte-identicalsrc/srcSet/sizes/loadingtofill+sizes="auto"— the only thing missing is a name and a paragraph for "unknown slot width, normal flow". Two slot shapes have no honest representation today and both collapse into that same case: anaspect-ratiobox, and a height-constrained slot. Both currently make callers declare aslotWidththeir CSS contradicts.2. Live defect:
widthswithoutslotWidthemitssizes="(min-width: undefinedpx) undefinedpx, 100vw". Browsers discard the media query and fetch the largest candidate on every screen — the exact failure the API exists to prevent.candidateWidths' missing-slotWidththrow is skipped whenwidthsis explicit, andderivedSizeshas no equivalent guard. Oneif.3. The
width->slotWidthrename is silent at compile time and fatal at render.widthis still legal — it is now the HTML attribute — so every call site written against the previous API type-checks and throws on first render. Requiringwidth/heightas a pair turns each one into a loud error at the right place. The JSDoc already says they come as a pair.4.
getImagePropsis reached past by both of its users. It has nofallback, so both Island call sites hand-build a bare{ src, alt }literal with nosrcSet, no dimensions and no cache dependency. Itscontextis optional and omitting it silently drops both the cache dependency andsetImageDefaults— and the guide's own Island example omits it. Give itfallback, makecontextrequired.5. Rename
ImageProps->ImgPropswhile it is still free. It is the type of what comes out ofgetImageProps, not the component's props — which is whatnext/imagemeans byImageProps, and whatJImagePropsmeans here. The link API next door already names the same conceptAnchorPropsand reservesLinkPropsfor the wrapper object.Also worth fixing in the guide:
alt(required) is documented at line 180 andfallbacknot at all, though roughly a third of real call sites need it; and "a plain instance does not resize images" — the single most surprising Jahia fact — sits at line 200, well after a reader would have concluded theirsrcSetis broken.Two smaller runtime issues:
sizes="auto"+preloadthrows, but those props legitimately arrive from different layers (a shared wrapper's default and a leaf view) and the wrapper cannot express the exclusion — a development warning plus a fallback to the derivedsizesis better than a 500 on a production page. And a node whosej:widthextraction never ran silently loses both its CLS reservation andloading="lazy", with nothing warning and the guide never namingj:width.