Solving my Image Dimension Problem with an Eleventy Transform
When migrating from WordPress to Eleventy, I wanted to automatically add width and height attributes to my images for better performance and layout stability. The official Eleventy image plugin felt overcomplicated for my needs, so I built a simple transform that inspects image files and adds dimensions to HTML img tags during the build process.
Eleventy Image Handling
When I migrated this site from WordPress to Eleventy, the image transform plugin was already included in the starter blog template I cloned. This plugin does a lot including outputting multiple sizes and formats. I think it was doing too much for what I needed. I really struggled trying to bring over my WordPress posts and images in a way that retained the old links. Even referencing a local image from Markdown wasn't working. I decided to pull out the 11ty image transform and manage images myself.
I wanted to start with automatically adding height and width attributes, so this is what I tried:
- Image plugin -- too complicated, removed
- Inspect the image plugin source to possibly copy just the height/width code -- too complicated
- Write my own plugin -- seems doable but probably overkill
- Write a transform -- this is starting to look the best path!
Eleventy transforms are run late in the build cycle ("postprocessing") and allow any transformations of the built page content. I had a good outline of how I would approach writing this, so I wrote a short spec for Copilot to help. I should have saved that prompt, but I could not get this code to work even with a bunch of adjustments and iterations I made.
After an overnight break I decided to go up a level and just ask Copilot for what I wanted :) This was the simple prompt, focusing just on the outcome:
write an eleventy transform that will automatically add height and width attributes to any found in the HTML source
This worked and with only minimal adjustments got me exactly what I needed!
Image Dimensions Transform
This is my solution for adding height and width attributes to image tags in the HTML output files. A few quick notes:
- This transform examines the DOM to find all the images, inspect the image file to find the height and width, then add those attributes to the image element
- We're only interested in .html output files
- If the page doesn't have any images, skip it (importantly for transforms: they need to just return the original unmodified content)
- Also skip any images hosted elsewhere (we're only processing local images)
To use this script, include this snippet in your eleventy.config.js
file:
/**
* Eleventy transform to add width and height to <img> tags
*/
eleventyConfig.addTransform(
"img-dimensions",
async function (content, outputPath) {
if (!outputPath || !outputPath.endsWith(".html")) return content;
const dom = new JSDOM(content);
const imgs = dom.window.document.querySelectorAll(
"img[src]:not([width]):not([height])",
);
// If no images, return the original content
if (imgs.length === 0) return content;
for (const img of imgs) {
try {
let src = img.getAttribute("src");
if (src.startsWith("http")) continue; // Skip remote images
// Remove leading slash if present
let imgPath = src.replace(/^\//, "");
let filePath = `./public/${imgPath}`;
let buffer = await promisify(readFile)(filePath);
let dimensions = imageSize(buffer);
if (dimensions.width && dimensions.height) {
img.setAttribute("width", dimensions.width);
img.setAttribute("height", dimensions.height);
}
} catch (e) {
console.log(
`Error processing image ${img.getAttribute("src")}: ${e.message}`,
);
}
}
return dom.serialize();
},
);
Also add these imports at the top of eleventy.config.js
:
import { promisify } from "util";
import { readFile } from "fs";
import { imageSize } from "image-size";
import { JSDOM } from "jsdom";
Finally, install the new library dependencies:
npm install jsdom image-size
Example
Here's an example from my Summarizing YouTube Videos with LLMs post. In the Markdown source file, the image is included with this markup:

After the build process and the image dimensions transform, the HTML has the alt text preserved and the newly calculated width and height attributes added:
<p><img src="/images/honey-scam-thumbnail.jpg" alt="Thumbnail for the Honey Influencer Scam YouTube video" width="300" height="180"></p>
Next
One thing I need to look at is the build time. It's not doing any caching, so each build needs to process the 400+ images. Right now my img-dimensions is taking up 23% of the time which isn't horrible but could be better:
[11ty] Benchmark 2668ms 23% 706× (Configuration) "img-dimensions" Transform
[11ty] Benchmark 5770ms 50% 661× (Configuration) "gitLastModified" Nunjucks Filter
[11ty] Copied 453 Wrote 696 files in 11.48 seconds (16.5ms each, v3.0.0)