Skip to content

Conversation

@Krishanthaudayakumara
Copy link
Owner

Description / Motivation

This PR implements responsive image support for the ImageTagHelper by adding srcset and sizes attribute functionality, enabling developers to output responsive images using Sitecore's built-in media resizing capabilities. The implementation matches the Content SDK (JSS replacement) behavior to ensure consistent output across .NET and JavaScript frameworks.

Key Changes:

  1. Added SrcSet and Sizes Properties: Extended the ImageTagHelper with new properties to support responsive image configuration for both <sc-img> and <img> tags.

  2. Multiple Input Format Support: The SrcSet property accepts three different input formats for maximum flexibility:

    • Anonymous objects: new object[] { new { w = 800 }, new { mw = 400 } }
    • Dictionary arrays: new Dictionary<string, object> { {"w", 800} }
    • JSON strings: [{"w": 800}, {"mw": 400}] (most JSS-like syntax)
  3. Content SDK Parameter Priority: Implements the same parameter precedence as Content SDK:

    • w (width) takes priority over mw (max width) for srcset descriptors
    • Only entries with valid w or mw parameters are included in srcset
    • Matches Content SDK's getSrcSet function behavior exactly
  4. Enhanced Parameter Merging:

    • Base imageParams are merged with individual srcSet parameters
    • srcSet parameters override imageParams for each srcset entry
    • Preserves existing query parameters (rev, db, la, vs, ts, hash, etc.)
    • Follows Content SDK's { ...imageParams, ...params } merge pattern
  5. URL Transformation:

    • Transforms /media/ URLs to /jssmedia/ (Content SDK compatible)
    • Preserves cache-busting and required parameters
    • Handles both XM Cloud and on-premise URL structures
  6. Enhanced HTML Output: Generates proper HTML5 responsive image markup:

    <img src="/~/jssmedia/image.jpg?quality=80" 
         srcset="/~/jssmedia/image.jpg?quality=80&w=800 800w, /~/jssmedia/image.jpg?quality=80&mw=400 400w"
         sizes="(min-width: 768px) 800px, 400px"
         alt="..." />
  7. Experience Editor Support: Works seamlessly with both normal rendering and Experience Editor editable markup.

  8. Backward Compatibility: All existing functionality remains unchanged; new features are opt-in.

Content SDK Compatibility:

The implementation now produces identical output to the Content SDK's Image component:

Content SDK (React):

<Image 
  field={imageField} 
  imageParams={{quality: 80}} 
  srcSet={[{w: 800}, {mw: 400}]} 
  sizes="(min-width: 768px) 800px, 400px" 
/>

ASP.NET Core SDK (Razor):

<sc-img asp-for="@Model.ImageField" 
        image-params='new { quality = 80 }'
        src-set='new object[] { new { w = 800 }, new { mw = 400 } }'
        sizes="(min-width: 768px) 800px, 400px" />

Both produce identical HTML:

<img src="/~/jssmedia/image.jpg?quality=80" 
     srcset="/~/jssmedia/image.jpg?quality=80&w=800 800w, /~/jssmedia/image.jpg?quality=80&mw=400 400w"
     sizes="(min-width: 768px) 800px, 400px" 
     alt="Image" />

Usage Examples:

<!-- Basic responsive image -->
<sc-img asp-for="@Model.HeroImage" 
        src-set='new object[] { new { w = 1200 }, new { w = 800 }, new { w = 400 } }'
        sizes="(min-width: 1200px) 1200px, (min-width: 800px) 800px, 400px" />

<!-- With base parameters -->
<img asp-for="@Model.ProductImage" 
     image-params='new { quality = 80, format = "webp" }'
     src-set='new object[] { new { w = 800, h = 600 }, new { mw = 400, mh = 300 } }'
     sizes="(min-width: 768px) 800px, 400px" />

<!-- JSON string format -->
@{
    string jsonSrcSet = """[{"w": 1000}, {"mw": 500}]""";
}
<sc-img asp-for="@Model.BannerImage" 
        src-set="@jsonSrcSet"
        sizes="(min-width: 960px) 1000px, 500px" />

This implementation ensures feature parity with the Content SDK while maintaining the familiar ASP.NET Core TagHelper syntax and full backward compatibility.

Testing

  • The Unit & Integration tests are passing.
  • I have added the necessary tests to cover my changes.
  • Added comprehensive test coverage for all three input formats
  • Added tests for Content SDK parameter priority (w > mw)
  • Added tests for parameter merging with imageParams and srcSet parameters
  • Added tests for cache-busting parameter preservation
  • Added tests for both <sc-img> and <img> tag scenarios
  • Added tests for Experience Editor editable markup integration
  • Added tests for entry filtering (only w/mw parameters included)
  • Added tests for graceful fallback when invalid JSON is provided

Terms

  • I agree to follow this project's Code of Conduct.

Fix #16

Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull Request Overview

This PR adds responsive image support to the ImageTagHelper by enabling srcset and sizes attributes with three input formats and preserves existing query parameters in generated media URLs.

  • Introduced SrcSet and Sizes properties with parsing and generation logic
  • Extended GetSitecoreMediaUri to merge original URL parameters with new ones
  • Updated tests to validate srcset, sizes, and parameter merging behavior

Reviewed Changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated 2 comments.

File Description
tests/.../ImageTagHelperFixture.cs Updated expected HTML for merged query parameters and added comprehensive srcset tests
src/.../ImageTagHelper.cs Added parsing (ParseSrcSet), merging (MergeParameters), descriptor (GetWidthDescriptor), and generation (GenerateSrcSetAttribute) methods, and wired up srcset/sizes in rendering
src/.../SitecoreFieldExtensions.cs Enhanced GetSitecoreMediaUri to preserve existing query parameters and added ParseUrlParameters helper
Comments suppressed due to low confidence (2)

tests/Sitecore.AspNetCore.SDK.RenderingEngine.Tests/TagHelpers/Fields/ImageTagHelperFixture.cs:956

  • There’s no test covering the case where SrcSet is provided as a single object (not an array or JSON string). Adding a test for that scenario would improve coverage for ParseSrcSet.
    private static ModelExpression GetModelExpression(Field model)

src/Sitecore.AspNetCore.SDK.RenderingEngine/Extensions/SitecoreFieldExtensions.cs:71

  • Missing using Microsoft.AspNetCore.WebUtilities; at the top of this file. QueryHelpers lives in that namespace, so add the import to prevent compilation errors.
                    url = QueryHelpers.AddQueryString(url, key, mergedParams[key]?.ToString() ?? string.Empty);

{
output.Attributes.Add(ScrAttribute, field.GetMediaLink(ImageParams));

// Add srcset if configured
Copy link

Copilot AI Jul 14, 2025

Choose a reason for hiding this comment

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

[nitpick] The blocks that add srcset and sizes attributes are duplicated in Process, GenerateImage, and MergeEditableMarkupWithCustomAttributes. Consider extracting shared logic into a helper method to reduce repetition.

Copilot uses AI. Check for mistakes.
{
try
{
var parsed = System.Text.Json.JsonSerializer.Deserialize<Dictionary<string, object>[]>(jsonString);
Copy link

Copilot AI Jul 14, 2025

Choose a reason for hiding this comment

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

Deserializing into Dictionary<string, object> causes values to be JsonElement instances, so calling ToString() on string parameters may include extra quotes. Consider using a converter or deserializing to a custom DTO to handle string vs numeric values cleanly.

Copilot uses AI. Check for mistakes.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Responsive image srcset support for Image tag helper

2 participants