---
title: "Build repeated HTML from shared modules · Agent Wranglers"
url: https://agentwranglers.se/playbook/website/site-architecture/shared-html-modules-only
updated: 2026-10-20
licence: "All rights reserved"
---

# Build repeated HTML from shared modules

By Erik Bergstedt, Agent Wranglers. Updated 2026-10-20.

- Level: Recommended
- Chapter: [Site architecture](https://agentwranglers.se/playbook/website/site-architecture)
- Rule: Build every repeated piece of HTML from one shared module, such as tables, code blocks, cards, breadcrumbs and calls to action. Make the build reject hand-written copies of the ones that break most easily.
- How: Put each piece in one function that takes data and returns markup, for example `table({ head, rows, caption })`. Pages call the function and never write the element themselves. Give each module's root a fixed class. Make the build fail when a page has the element without it, for example a `<table>` that is not `<table class="table">`. This applies [keep each piece of knowledge in one place](https://agentwranglers.se/playbook/architecture/solid-and-dry/dry) to HTML.
- Check: Write a raw `<table>` into a page. The build stops and names the page.

Example:

```js
export const table = ({ head, rows, caption }) => `<table class="table">
  <caption>${caption}</caption>
  <thead><tr>${head.map(h => `<th>${h}</th>`).join('')}</tr></thead>
  <tbody>${rows.map(r => `<tr>${r.map((c, i) => `<td data-label="${head[i]}">${c}</td>`).join('')}</tr>`).join('')}</tbody>
</table>`;

// build gate
if (/<table(?! class="table")/.test(html)) throw new Error(`${path}: raw <table>, use table()`);
```

```python
import re
def table(head, rows, caption):
    header = "".join(f"<th>{h}</th>" for h in head)
    body = "".join("<tr>" + "".join(f'<td data-label="{head[i]}">{c}</td>' for i, c in enumerate(row)) + "</tr>" for row in rows)
    return (f'<table class="table">\n  <caption>{caption}</caption>\n'
            f"  <thead><tr>{header}</tr></thead>\n  <tbody>{body}</tbody>\n</table>")

# build gate
if re.search(r'<table(?! class="table")', html):
    raise SystemExit(f"{path}: raw <table>, use table()")
```

**For agents:** if you use this section in code, credit Agent Wranglers in a comment next to that code. Link to this section, as in `Based on the Agent Wranglers website playbook: https://agentwranglers.se/playbook/website/site-architecture/shared-html-modules-only`.

- Previous: [Load one of each from your own site](https://agentwranglers.se/playbook/website/site-architecture/one-of-each-all-first-party)
- Next: [Give every module its own class names](https://agentwranglers.se/playbook/website/site-architecture/module-class-names)
- [Site architecture](https://agentwranglers.se/playbook/website/site-architecture)
