Skip to content

Conversation

@Vaibhav91one
Copy link

@Vaibhav91one Vaibhav91one commented Oct 11, 2025

Problem

When AI transformations return 423 (Locked) status during processing, broken image icons appear during polling.

PR for issue #514

Solution

Added a shimmer placeholder that displays during 423 polling:

  1. Hide broken icon synchronously via DOM manipulation
  2. Show CSS shimmer during polling
  3. Smooth transition when image loads
// Key change in onError handler
const img = options.target as HTMLImageElement;
img.style.opacity = '0';
img.style.visibility = 'hidden';
setIsPolling(true);
await pollForProcessingImage({ src });
setIsPolling(false);

Changes

  • File: src/components/CldImage/CldImage.tsx
  • Added: Shimmer placeholder with CSS animation

Testing

<CldImage removeBackground src="your-image" />

Hard refresh to see shimmer during AI processing.

@vercel
Copy link

vercel bot commented Oct 11, 2025

Someone is attempting to deploy a commit to the Cloudinary DevX Team on Vercel.

A member of the Team first needs to authorize it.

@Vaibhav91one
Copy link
Author

Hi, @devpatocld. Please take a look at this.

@devpatocld
Copy link
Collaborator

@Vaibhav91one PR under review. Please be patient! Thank you

Copy link
Contributor

@eportis-cloudinary eportis-cloudinary left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi @Vaibhav91one! Thank you so much for this contribution. Unfortunately I don't think we can accept it in its current state.

A solution must be unopinionated about what the visual placeholder state is - doing very little by default and adding easy styling hooks for overriding. The shimmering here, with hardcoded colors, timing, etc. looks great in some contexts but certianly will not suit every context, and the un-turn-off-able motion likely violates WCAG requirements. We can't do all of that by default, and this PR doesn't provide users a way to supply their own placeholder styles. I would love it if this simply added a class or data- attribute, and perhaps a default style that set a transparent gray background, which was easy to override.

The addition of a container element is also problematic. Users may depend on the specific DOM structure <CldImage> returns, and this change would break those assumptions. If possible, instead of hiding the image, and showing its container, perhaps we could replace the src/srcset with a transparent gif, until the polling is complete.

I do think that the new useState added here (isPolling) is going to be the foundation of a solution here.

Does that feedback make sense? I've tried to outline what is not acceptable here, but am not entirely sure my suggested ways forward would work, and know they are incomplete. It's more than possible this will take a few tries and more discussion to get right. Do you want to take another swing at this?

@Vaibhav91one
Copy link
Author

Yes, Absolutely @eportis-cloudinary . Thank you for the feedback. After reviewing the feedback, I wanted to discuss two approaches and would like your opinion on it.

  1. Render Prop Pattern (Just like in CldUploadWidget).
// Default - no changes
<CldImage 
  src="images/woman-headphones" 
  width="500" 
  height="500" 
  alt="Portrait" 
/>

// With custom polling UI
<CldImage 
  src="images/woman-headphones" 
  width="500" 
  height="500" 
  alt="Portrait"
>
  {({ isPolling }) => isPolling && (
    <div style={{
      position: 'absolute',
      inset: 0,
      display: 'flex',
      alignItems: 'center',
      justifyContent: 'center',
      background: 'rgba(255, 255, 255, 0.9)'
    }}>
      <span>Processing...</span>
    </div>
  )}
</CldImage>

// Advanced - conditional styling
<CldImage 
  src="images/woman-headphones" 
  width="500" 
  height="500" 
  alt="Portrait"
>
  {({ isPolling }) => (
    <>
      {isPolling && <Spinner size={40} />}
      {isPolling && <p>AI processing in progress</p>}
    </>
  )}
</CldImage>

This accepts optional children function that receives isPolling boolean. User has full control over rendering logic. This matches CldUploadWidget pattern.

  1. Simple Prop
// Default - no changes
<CldImage 
  src="images/woman-headphones" 
  width="500" 
  height="500" 
  alt="Portrait" 
/>

// With custom polling UI
<CldImage 
  src="images/woman-headphones" 
  width="500" 
  height="500" 
  alt="Portrait"
  pollingFallback={
    <div style={{
      position: 'absolute',
      inset: 0,
      display: 'flex',
      alignItems: 'center',
      justifyContent: 'center',
      background: 'rgba(255, 255, 255, 0.9)'
    }}>
      <span>Processing...</span>
    </div>
  }
/>

// With component
<CldImage 
  src="images/woman-headphones" 
  width="500" 
  height="500" 
  alt="Portrait"
  pollingFallback={<Spinner />}
/>

This approach accepts optional pollingFallback prop with React component. Automatically shows/hides during polling. but there is no access to polling state for custom logic.

@Vaibhav91one
Copy link
Author

Hi @eportis-cloudinary @devpatocld any update on the above?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants