HTML includes
A zero-dependency Web Component for reusable HTML fragments.
Overview
Live Wires uses a custom <html-include> element to load HTML fragments at runtime. This enables you to share headers, footers, navigation, and other repeated content across pages without build-time processing.
Key features
- Zero dependencies—Pure Web Components API, no libraries
- Runtime loading—Fragments are fetched when the page loads
- Script support—JavaScript in includes executes correctly
- Error handling—Shows debug messages in development mode
- Standard HTML—No special syntax or templating language
Basic usage
1. Load the Web Component first
The <html-include> element must be defined before any instances appear in the document. Include the script in your <head>:
<head>
<!-- Load Web Component first (required!) -->
<script type="module" src="/src/js/main.js"></script>
<!-- Now includes will work -->
<html-include src="/_includes/head.html"></html-include>
</head>
2. Use the element anywhere
<body>
<html-include src="/_includes/header.html"></html-include>
<main>
<!-- Your page content -->
</main>
<html-include src="/_includes/footer.html"></html-include>
</body>
3. Create your include files
Store reusable fragments in /public/_includes/:
<!-- /public/_includes/header.html -->
<header class="py-3 px-4">
<nav class="cluster cluster-space-between">
<a href="/" class="logo">
<img src="/img/logo.svg" alt="Site Name">
</a>
<ul class="cluster">
<li><a href="/">Home</a></li>
<li><a href="/about/">About</a></li>
<li><a href="/contact/">Contact</a></li>
</ul>
</nav>
</header>
Path conventions
The src attribute accepts both absolute and relative paths:
Absolute paths (recommended)
<!-- Always works, regardless of page location -->
<html-include src="/_includes/header.html"></html-include>
Relative paths
<!-- From /docs/index.html -->
<html-include src="/_includes/header.html"></html-include>
Absolute paths starting with / are resolved from the site root, making them more portable. Use relative paths when the include is specific to a section.
Passing classes
Classes on the <html-include> element are preserved:
<html-include class="bg-subtle" src="/_includes/nav.html"></html-include>
This lets you apply styling or layout to the include wrapper without modifying the include file itself.
JavaScript in includes
Scripts inside include files are re-executed after loading. This works because the component explicitly creates new <script> elements:
<!-- /public/_includes/analytics.html -->
<script>
console.log('Analytics loaded');
// Your tracking code here
</script>
Both inline scripts and external scripts (with src) are supported.
Error handling
If an include fails to load, the component logs an error to the console:
HtmlInclude: failed to load /_includes/missing.html
In development mode (Vite dev server), a visible error message is displayed in place of the include:
Failed to load include: /_includes/missing.html
This helps catch typos and missing files during development.
Common includes
A typical Live Wires project uses these includes:
/_includes/head.html- Meta tags, title, favicon, additional CSS
/_includes/header.html- Site header with logo and navigation
/_includes/footer.html- Site footer with copyright, links
/_includes/nav-*.html- Section-specific navigation (e.g., nav-docs.html, nav-guide.html)
SEO considerations
Content loaded via JavaScript is generally indexed by modern search engines. Google executes JavaScript and can see client-rendered content. However, there are practical considerations:
Best practice: Use includes for
- Headers and footers (repeated across pages)
- Navigation (links are crawlable)
- Repeated UI elements
Keep in main HTML
- Page titles and meta descriptions
- Primary content unique to each page
For build-time includes
If you prefer pre-rendered HTML (faster initial paint, works without JavaScript), consider:
vite-plugin-handlebarsfor static site generation- 11ty, Astro, or similar static site generators
Live Wires' HTML and CSS patterns work with any build tool.
How it works
The component is defined in src/js/html-include.js:
- When a
<html-include>element connects to the DOM,connectedCallback()fires - The
srcattribute is read - The HTML is fetched via
fetch() - Content is parsed using a
<template>element - The parsed content replaces the element’s children
- Any
<script>tags are re-created to execute
Total code: ~60 lines. No dependencies.
Troubleshooting
Include not loading
- Check that
main.jsis loaded before the include element - Verify the
srcpath is correct (check browser console) - Ensure the include file exists at the specified path
Styles not applying
- Include content inherits styles normally—no shadow DOM
- Check that your CSS is loaded before the include renders
Scripts not running
- Scripts execute after the include loads
- If accessing DOM elements, ensure they exist (use
DOMContentLoadedor put scripts at end)