Querying alt tags for inline images in 11ty site with Sanity media library plugin

21 replies
Last updated: Mar 19, 2021
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!

So I've got it working with an async function but it's clear that I should be materializing the asset fields in the main query, rather than querying for the alt tag individually for each inline image.
My schema has a page document type that contains an array which in turn contains objects.

One of the objects is named 'content' and is comprised of a single block content field. Can anyone help me figure out a groq query to materialise the alt field I need for the inline image in this block content?

I discovered that the media library stores the alt field below sanity.imageAsset

Any help gratefully received as always
😉
*[_type == "page" && title != ""] {

title,

slug,

headerBlocks,

mainBlocks[],

...,

_type == "content" => {

...,

blocktext[]{

...,

children[]{

...,

_type == "image" => {


"alt": @.imageAsset->alt,

}

}

}

},

}
Not giving an error, but not materializing the alt field still. Could you have a look for me
user A
?
Are you getting results back as deep in your query as
children[]
?
Thanks for the reply. Yes. I'm getting all the fields back but not the alt.
Is it okay to nest those _type == "" clauses?
I think it should be fine. If you replace
"alt": @.imageAsset->alt,
with
...
, what do you get back?
I seem to get the same result
Do any items of the
children
array have the type of image?
There is no children array in the results. This might be the issue.
I can see mainblocks -&gt; 0 -&gt; blocktext -&gt; 0,1,2,3,4,5,6,7,8
Sounds like it, yes. I might try commenting out all the ellipses to limit noise, then bring them back in once you’re getting your alt data.
Are any of the
blocktext
items
children[]
?
No, they are numbered 0-8
8 holds the image
okay
It’s tough to say without seeing the query result, but maybe remove
children[]{
and its corresponding
}
.
Okay. I'll keep trying. I discovered vision so it should be possible. At least I know I'm not completely off the track now, thanks.
Another approach I might use myself is to remove the entire projection (i.e., get all the data) then Inspect the JSON and trace out the path.
Feel free to post your schema and/or query results (redacting anything private) if you try a bit more and are still stuck.
Thanks I will. I'm really pleased to have got the serializer function working. Getting the alt text in is the icing on the cake!
I applaud your tenacity. We’ll get there! 🙂

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?