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 image 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)
- Simple Lossless Image Compression
- Solving my Image Dimension Problem with an Eleventy Transform
- How to Add Playwright Automated Tests to an Eleventy Static Blog
- Copilot is my Copilot
- Migrating WordPress To Eleventy
- Proper Sitemap Update Dates for Eleventy
- Migrated to Static Site (Eleventy)