MDX component overrides in Astro - img vs Image
This one bit me and I couldn’t figure out why for a while so writing it down.
I have a custom Image component that wraps images with some extra styling — negative margins so the image bleeds wider than the text, rounded corners, lazy loading. In my blog post template I pass it to the MDX renderer:
<Content components={{Image}} />
Looks right. But markdown images like  still rendered as plain <img> tags without my wrapper.
The fix
Markdown images render as <img> (lowercase). The components prop maps HTML element names, not component names. So you need:
<Content components={{img: Image}} />
Lowercase img maps to the HTML element that markdown produces. Uppercase Image would only work if you explicitly write <Image /> in your MDX file.
One more thing
If you use local images in MDX with relative paths like , Astro passes the src prop as an object with {src, width, height} instead of a plain string. Your component needs to handle that:
---
const {src, ...rest} = Astro.props
const imgSrc = typeof src === 'object' && src !== null ? src.src : src
---
<img src={imgSrc} {...rest} loading="lazy" decoding="async" />
Small thing but it will hopefully save you some debugging and headscratching.