Skip to main content

Little Dummies: Simple FPO Content Helpers

By Tyler Sticka

Published on March 12th, 2026

Topics

I was delighted to present this talk at the final (for now) episode of The Eleventy Meetup:

Eleventy Build Awesome is great for rapid prototyping! Tyler shows off a few of his favorite shortcodes, filters and other techniques to quickly populate interactive mockups and wireframes with “dummy” or FPO (for placement only) content.

You can watch the presentation here:

These are the main code samples from my slides, consolidated below for easy reference.

With the Chance dependency:

import Chance from "chance";
let chance;

export default function (method, ...args) {
  // Support JSON string for first argument
  if (typeof args[0] === "string") {
    args[0] = JSON.parse(args[0]);
  }

  // Instantiate Chance the first time
  if (!chance) {
    chance = new Chance();
  }

  // If the method exists, return its output
  if (typeof chance[method] === "function") {
    return chance[method](...args);
  }

  // Otherwise, log an error but proceed
  console.error(`[chance] No method named ${methodName}`);
  return "";
}Code language: JavaScript (javascript)

With our Simple SVG Placeholder dependency:

import simpleSvgPlaceholder from "@cloudfour/simple-svg-placeholder";

/**
 * Modify these to suit the project!
 * @see https://github.com/cloudfour/simple-svg-placeholder#option-reference
 */
const defaults = {
  bgColor: "rgb(0 0 0 / 0.8)",
  textColor: "white",
};

export default function (width, height, options = {}) {
  // Support JSON string for argument
  if (typeof options === "string") {
    options = JSON.parse(options);
  }

  return simpleSvgPlaceholder({...defaults, width, height, ...options});
}Code language: JavaScript (javascript)

Using the Iconify API via Eleventy Fetch:

import EleventyFetch from "@11ty/eleventy-fetch";

const apiUrl = "https://api.iconify.design";

const fetchOptions = {
  duration: "1y",
  type: "json",
};

const defaultAttr = {
  xmlns: "http://www.w3.org/2000/svg",
  class: "icon",
};

// Get a specific set:name icon string
async function getSpecificIcon(icon) {
  // If already specific, do nothing
  if (icon.includes(":")) {
    return icon;
  }

  const searchUrl = `${apiUrl}/search?query=${icon}&limit=1`;
  const searchData = await EleventyFetch(searchUrl, fetchOptions);
  const results = searchData.icons || [];

  if (results.length === 0) {
    throw new Error(`No icon found for ${icon}`);
  }

  return results[0];
}

// { class: "icon", width: 120 }
// => 'class="icon" width="120"'
// (You should escape this stuff for production)
function objectToAttributeString(obj) {
  return Object.entries(obj)
    .map(([key, value]) => `${key}="${value}"`)
    .join(" ");
}

export default async function (icon, attr = {}) {
  // Support JSON strings for attributes
  if (typeof attr === "string") {
    attr = JSON.parse(attr);
  }

  try {
    icon = await getSpecificIcon(icon);
    const [setName, iconName] = icon.split(":");
    const iconDataUrl = `${apiUrl}/${setName}.json?icons=${iconName}`;
    const iconData = await EleventyFetch(iconDataUrl, fetchOptions);

    if (typeof iconData !== "object") {
      throw new Error(`Request for ${icon} returned ${iconData}`);
    }

    const { width, height } = iconData;
    const { body } = iconData.icons[iconName];
    const attrString = objectToAttributeString({
      ...defaultAttr,
      "data-icon": icon,
      viewBox: `0 0 ${width} ${height}`,
      width,
      height,
      ...attr
    });

    return `<svg ${attrString}>${body}</svg>`;
  } catch(err) {
    console.error(`[iconify] ${err.message}`);
    return "";
  }
}Code language: JavaScript (javascript)

More references from the talk (other than dependencies in the previous section):

Two questions stood out to me during a live Q&A following my presentation:

Do you only prototype in Eleventy / Build Awesome?

No! Sometimes the teams we work with already have an environment with a suitable playground, or a different stack they’re more familiar with. But Build Awesome is a great fallback due to its stability, performance, flexibility and small footprint.

Do you share these sorts of helpers between projects?

We start from a private, opinionated template repository, which we tailor to the project’s needs. After a major milestone, we’ll see if anything we diverged on deserves to be added back to the template repo to benefit future projects. This allows us to easily adapt the helpers to the needs of the project without sweating breaking changes.

Big thanks to Sia Karamalegos for having me, Zach Leatherman for creating Build Awesome (new Kickstarter launching soon) and encouraging my unique possum interpretations, and especially everyone who attended the meetup!

If you want to see Cloud Four’s process in action, get in touch! We’re always looking for our next web app design challenge.

Leave a Comment

Please be kind, courteous and constructive. You may use simple HTML or Markdown in your comments. All fields are required.