How to query alt tags for inline images in block content serializers?

21 replies
Last updated: Jan 28, 2026
Good morning kind Sanity people.
I have been striving to figure out how to display inline images in block content with responsive sizes and alt tags for an 11ty site. I now have the srcset working after reverse engineering
https://github.com/brob/eleventy-plugin-sanity-image . Now I need help to understand how I can query the alt tag for the image from inside my serializer function. I'm using the excellent Sanity media library plugin (https://www.sanity.io/plugins/sanity-plugin-media-library ) to set the alt tags. My serializer function is using @sanity/image-url to query Sanity to build the image urls. How can I query the alt tag I set in the media library?
AI Update

Good morning! I understand you're working on displaying inline images in block content (Portable Text) for an 11ty site and need to query the alt text that you've set using the sanity-plugin-media-library. Let me help you understand how to access this data.

How the Media Plugin Stores Alt Text

The sanity-plugin-media (the community plugin you're referring to) stores metadata like altText, title, and description directly on Sanity's native asset documents. These fields are part of Sanity's standard asset schema, so they're stored at the asset level, not in a custom namespace.

Querying Alt Text in Your Serializer

When you're building your serializer function for Portable Text images, you'll need to expand the asset reference to get the altText field. Here's how to structure your GROQ query:

*[_type == 'your-document-type'] {
  body[] {
    ...,
    _type == 'image' => {
      ...,
      asset-> {
        _id,
        url,
        altText,
        description,
        metadata {
          dimensions
        }
      }
    }
  }
}

The key part is asset-> which dereferences the asset reference, allowing you to access fields like:

  • altText - The alt text field
  • title - The title field
  • description - The description field
  • originalFilename - The original filename

In Your Serializer Function

When you're using @sanity/image-url in your serializer, you should have access to the full image object. Here's a conceptual example of how you might structure your serializer:

const serializers = {
  types: {
    image: ({value}) => {
      // value.asset should contain your dereferenced asset data
      const imageUrl = urlFor(value)
        .width(800)
        .auto('format')
        .url();
      
      return `<img 
        src="${imageUrl}" 
        srcset="${generateSrcSet(value)}"
        alt="${value.asset.altText || ''}"
        loading="lazy"
      />`;
    }
  }
};

Important Notes

  1. Field Location: The altText field is stored directly on the sanity.imageAsset document, not in a custom namespace like tags would be (tags are stored in opt.media.tags).

  2. Query Expansion: Make sure your initial GROQ query expands the asset reference (asset->) to include the fields you need. Without this, you'll only have the asset reference ID.

  3. Fallback Values: Always provide fallback values for alt text to ensure accessibility even if editors haven't set it.

Alternative: Using Image URL Builder

If you're using @sanity/image-url, remember that it only generates URLs—it doesn't automatically include alt text or other metadata. You'll need to pass these separately to your image markup.

The image URL builder respects crop and hotspot settings automatically when you pass it the full image object (not just the asset), but you still need to handle alt text, captions, and other metadata separately in your serializer.

If you're still having trouble accessing the alt text, make sure your GROQ query is properly dereferencing the asset. The critical piece is using asset-> in your query to expand the reference and get all the asset fields including altText. Good luck with your 11ty site!

Show original thread
21 replies

Sanity – Build the way you think, not the way your CMS thinks

Sanity is the developer-first content operating system that gives you complete control. Schema-as-code, GROQ queries, and real-time APIs mean no more workarounds or waiting for deployments. Free to start, scale as you grow.

Was this answer helpful?