Skip to content

Image API: five things to fix before release #767

Description

@romain-pm

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.

Metadata

Metadata

Assignees

No one assigned

    Labels

    featA new feature

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions