Skip to content

[JEWEL-1239] Render failed to load images as hyperlinks#3421

Open
AlexVanGogen wants to merge 2 commits intoJetBrains:masterfrom
AlexVanGogen:alexvangogen/JEWEL-1239-broken-images-as-links
Open

[JEWEL-1239] Render failed to load images as hyperlinks#3421
AlexVanGogen wants to merge 2 commits intoJetBrains:masterfrom
AlexVanGogen:alexvangogen/JEWEL-1239-broken-images-as-links

Conversation

@AlexVanGogen
Copy link
Contributor

@AlexVanGogen AlexVanGogen commented Feb 12, 2026

Warning

This PR is built on top of image scaling PR. It's very hard to decouple them as they both heavily change the same source code. Please disregard the earlier commit message, only the last one is relevant to this change. I'll update the branch once the above PR gets merged.

Images that fail to load are now rendered as clickable hyperlinks instead of showing raw Markdown syntax or blank placeholders.

Changes

Failed Image Handling:

  • Images that fail to load are replaced with clickable links showing the alt text (or URL if no alt text)
  • A broken image indicator (🖼) is prepended to the link text

Loading States:

  • Added ImageRenderResult sealed class with Loading, Success, and Failed states
  • Loading indicator is shown while images are being fetched
  • Previously failed images skip the loading indicator on retry to prevent flickering

API Changes:

  • New ImageRendererExtension.renderImage method returning ImageRenderResult for explicit state handling
  • Deprecated renderImageContent method (preserved for backward compatibility)

Evidence

Switch between successful and failed loading (valid/invalid image source)

Screen.Recording.2026-01-27.at.19.07.56.mov

One broken URL doesn't affect other images in a block

Screen.Recording.2026-02-12.at.16.52.28.mov

Changing alt text affects failed image rendering and doesn't cause flickering (loading indicator <-> broken link) (don't ask why badges from Jewel README didn't render :))

Screen.Recording.2026-01-27.at.19.06.49.mov

Release notes

⚠️ Important Changes

  • Images that fail to load are now rendered as clickable links instead of showing raw Markdown syntax

New features

  • JEWEL-1239 Render failed to load images as hyperlinks (#3421)

Deprecated API

  • Deprecated ImageRendererExtension.renderImageContent; use renderImage instead, which provides explicit loading/success/failed states

Update placeholders during measurement phase based on available width.
Fast path is available for text without images
or with only images with zero width,
so no extra computations and compositions for a regular text.

This solution preserves `maxIntrinsicWidth`.
It's done to keep the right proportions
during resize in some container composables, i.e., tables.

Notable change: FlowRow isn't used anymore
if a paragraph or a heading contains only of images.
This was done for several reasons, the main being
to not reserve vertical space if images fail to load.
However, the better alternative I think would be
to render this image as a hyperlink (like GH does).

Possible alternatives:
- Split a text with images into different composables
  and arrange them in a `FlowRow`. While it does the job,
  it breaks behavior based on text continuity.
  For example, the text is copied with line breaks.
  Visibly, if an image fits the available width
  and there's place for a portion of text on the right,
  this text will nevertheless appear below the text
  (as it's a different composable).
- Wrap an image in a `BoxWithConstraints`.
  It would limit Markdown extensions rendering a lot,
  as it prohibits possible containers to measure themselves
  by using children's intrinsics.
  Note that `FlowRow` doesn't cause such a problem
  because it defines custom intrinsic measurement
  (see `FlowMeasurePolicy`).
- Custom `SubcomposeLayout` with a custom intrinsic measurement
  instead of a `FlowRow`. `FlowRow` downscales an image properly,
  but it keeps the reserved vertical space,
  so other content is rendered far enough
  as if the image were unscaled.
  While theoretically possible, that would be too challenging
  to implement, and maybe not immensely required for our case --
  images right in-between text shouldn't be a common practice.
  Plus, it's inferior to the current solution in a sense that
  we only have one composable, in fact; breaking it into parts
  causes potential visibility problems and accessibility issues,
  as described above.
@AlexVanGogen AlexVanGogen force-pushed the alexvangogen/JEWEL-1239-broken-images-as-links branch from 06ef0cc to 13ae3aa Compare February 27, 2026 16:57
- Show a hyperlink with an image's alt text, preceded by an icon 🖼
- Added a loading indicator for images
- Deprecated `ImageRendererExtension.renderImageContent`
- Added tests
@AlexVanGogen AlexVanGogen force-pushed the alexvangogen/JEWEL-1239-broken-images-as-links branch from 13ae3aa to 00b4380 Compare February 27, 2026 17:24
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants