Indieweb Starter Blog
← Back to Blog
Featured image for Building the IndieWeb Blog Template — A Technical Postmortem

Building the IndieWeb Blog Template — A Technical Postmortem

What broke, how we fixed it, and advice for Eleventy devs

Published on by Your Name4 min read

This post documents the technical journey of turning a clean Eleventy starter into a robust, reusable blog template with end‑to‑end tests. It highlights where things broke, how they were fixed, and practical advice for building resilient 11ty sites.

Scope & Goals

  • Template-first mindset: Remove personal identifiers; make customization predictable via src/_data/site.json.
  • Stable E2E tests: Use Playwright for cross-browser checks (desktop + mobile).
  • A11y & UX: Keyboard navigation, skip links, and predictable focus order.
  • SEO previews: Open Graph and Twitter cards with a sensible default image.
  • Deployment: One-click deploy and repeatable builds.

Where We Got Stuck (and Fixes)

1) Mobile navigation visibility

  • Symptom: Mobile tests couldn’t find nav links; menu was hidden by default.
  • Root cause: #primary-nav started with a hidden class in src/_includes/layouts/base.njk.
  • Fix: Remove hidden and ensure it renders as block on mobile. This made selectors stable and avoided strict-mode conflicts.

2) Desktop width constraints

  • Symptom: Layout width expectations failed on large screens.
  • Root cause: Header/nav containers lacked a max width.
  • Fix: Constrain to max-w-4xl on containers in base.njk to achieve consistent line-length and pass tests.

3) Overlapping controls and click interception

  • Symptom: Dark mode toggle and search were intermittently unclickable (intercepted by surrounding containers), especially on mobile.
  • Root cause: Header controls + search placement caused overlap in certain viewports.
  • Fix: Move the search form into the nav area and relocate the dark mode toggle to avoid pointer interception. This also simplified focus order.

4) Keyboard navigation focus order

  • Symptom: Tests expected the first nav link to be focused after two Tabs (after the skip link), but the brand/link or utility controls received focus first.
  • Root cause: Natural DOM/tab order favored brand and header utilities.
  • Fixes:
    • Make the brand link non-focusable (tabindex="-1").
    • Provide a visible-on-focus skip link and a focus target on <main id="main-content" tabindex="-1">.
    • Keep utility controls out of the tab order and move the dark toggle into the nav block.

5) Ambiguous selectors in tests

  • Symptom: Playwright strict-mode violations due to multiple .grid matches.
  • Root cause: Test targeted a generic selector expected to be unique.
  • Fix (tests): Narrow the selection via .first() in tests/e2e/responsive.spec.js.

6) BrowserSync websocket error noise

  • Symptom: Repeated Invalid WebSocket frame: RSV1 must be clear messages in logs.
  • Root cause: BrowserSync/WS interaction; not a functional site bug.
  • Fix: Treat as low priority; continue tests. Consider disabling live reload in CI for noise reduction.

7) SEO preview cards

  • Need: Reliable previews for social sharing without per-page boilerplate.
  • Solution: In src/_includes/layouts/base.njk, add OG + Twitter tags.
    • Canonical URL from site.url + page.url.
    • og:title, og:description from page or site.
    • Image resolution logic supports a page image front matter or defaults to /screenshot.png.

Advice for Eleventy Developers

  • Start with testable markup

    • Favor stable IDs or scoped selectors where appropriate.
    • Avoid hiding critical nav by default on smallest breakpoints unless you test toggles explicitly.
  • Design keyboard flows early

    • Add a skip link at the top: "Skip to content".
    • Make the main region focusable: <main id="main-content" tabindex="-1">.
    • Ensure the first actionable element is predictable after the skip link.
  • Prevent click interception

    • Test on mobile widths; watch for absolutely-positioned wrappers intercepting clicks.
    • Keep interactive controls in their own container and verify with Playwright’s pointer-interception errors.
  • Keep selectors resilient

    • Strict mode in Playwright is great—use .first() or more specific locators when multiple matches are expected.
    • Prefer role-based queries where possible.
  • Centralize configuration

    • Put owner, URLs, and social accounts in src/_data/site.json.
    • In templates, always fall back to site-level defaults.
  • Ship good previews with defaults

    • Add OG/Twitter tags once in your base layout.
    • Provide a default image (e.g., /screenshot.png) and allow per-page overrides via image front matter.
  • Treat noisy dev tooling errors pragmatically

    • If live-reload tooling logs errors but the site works and tests pass, deprioritize for launch; circle back later.
  • Automate deployments

    • Keep builds deterministic. Verify the live site’s meta tags with official validators after deploy.

Files Touched (Highlights)

  • src/_includes/layouts/base.njk — nav visibility, width constraints, skip link, main focus, search placement, dark toggle relocation, SEO meta.
  • tests/e2e/responsive.spec.js — more specific locator to pass strict mode.
  • README.md — preview image at the top for quick visual context.
  • src/_data/site.json — centralized site info used for meta tags.

What I’d Do Next

  • Reduce test flakiness with explicit focus waits where necessary.
  • Optionally disable BrowserSync websocket during test runs.
  • Add Lighthouse CI and HTML validation in CI for ongoing quality.

If you’re building with Eleventy: design for testability, keep accessibility first, and default your SEO. The rest becomes much easier to maintain.

Your Name

About Your Name

Your author bio goes here. Describe yourself and what you write about.

About Your Name

I'm passionate about thoughtful writing, meaningful connections, and building a more human web. This is my corner of the internet where I share ideas, experiences, and discoveries.

Join the Newsletter

Get thoughtful updates delivered to your inbox. No spam, just meaningful content.

Related Posts

Responses

Loading webmentions...