# Patterns

> Core DOM-first patterns for building malleable documents with ClayJS: locality of concern, inline code, template cloning, delegation, and DOM state.

Source: https://clayjs.com/docs/patterns/

Malleable documents keep structure, state, and behavior together in the DOM. These seven patterns cover the building blocks; see [App architecture](https://clayjs.com/docs/guide/architecture/) for how they fit together in full documents.

## Locality of concern

Keep markup, styling, and behavior together in the element they belong to rather than splitting them across separate files. When structure and behavior sit in one place, you can read the element and see everything it does.

```html
<div class="counter">
  <h3>Counter: <span>0</span></h3>
  <button type="button" editmode:onclick inert-onclick="this.previousElementSibling.querySelector('span').textContent++" show-when:editmode="true">
    Increment
  </button>
</div>
```

## Inline code

Inline event attributes (`onclick`, `oninput`, `onchange`) keep small behaviors local to the element where the interaction happens. Use [`editmode:onclick`](https://clayjs.com/docs/attributes/) when a handler should run only in edit mode and stay inert for visitors:

```html
<button type="button" onclick="this.textContent = 'Clicked'">Click me</button>
<input oninput="this.nextElementSibling.textContent = this.value">
<select onchange="document.body.dataset.theme = this.value">
  <option value="light">Light</option>
  <option value="dark">Dark</option>
</select>
```

When you want concise inline queries across multiple elements, load the [`all.js`](https://clayjs.com/docs/dom-helpers/) satellite (`https://clayjs.com/v1/all.js`) and use `All`:

```html
<button type="button" onclick="All.panel.classList.toggle('expanded')">Toggle panels</button>
<button type="button" editmode:onclick inert-onclick="All.item.filter(el => el.dataset.status === 'draft').forEach(el => el.remove())">
  Clear drafts
</button>
```

## Template clone

Build dynamic lists by cloning a `<template>` element rather than assembling HTML strings in JavaScript. Keep the `<template>` outside the list and write its controls in their active form (see [Edit mode and view mode](https://clayjs.com/docs/guide/edit-mode/)).

For a button that adds an item in edit mode, use [`add-from` and `add-to`](https://clayjs.com/docs/attributes/). A click clones the `<template>` named by `add-from`, assigns the clone a fresh `data-id`, appends it to the container named by `add-to`, and focuses its first editable field:

```html
<ul id="tasks">
  <li class="task" data-id="t-1">
    <input type="checkbox" persist viewmode:disabled disabled>
    <span class="title" editmode:contenteditable inert-contenteditable="plaintext-only">Write the brief</span>
  </li>
</ul>

<template id="task-tpl">
  <li class="task">
    <input type="checkbox" persist viewmode:disabled>
    <span class="title" editmode:contenteditable contenteditable="plaintext-only"></span>
  </li>
</template>

<button type="button" add-from="#task-tpl" add-to="#tasks" show-when:editmode="true">+ Add task</button>
```

When adding an item requires extra logic such as logging activity or wrapping the change in an [undo](https://clayjs.com/docs/plugins/undo/) commit, clone `template.content.firstElementChild` in a command function as shown in [App architecture](https://clayjs.com/docs/guide/architecture/).

## Event delegation

Because records are added, removed, and merged dynamically, attach one delegated listener on `document` inside `clay.start()` rather than binding listeners to individual elements. A delegated listener survives [live sync](https://clayjs.com/docs/plugins/live-sync/) merges and undo replays that replace or re-insert nodes:

```html
<script>
clay.start(() => {
  document.addEventListener("click", (event) => {
    const button = event.target.closest("[data-action]");
    if (!button || !clay.isEditMode) return;

    if (button.dataset.action === "complete") {
      button.closest(".task").dataset.status = "done";
    }
    if (button.dataset.action === "delete") {
      button.closest(".task").remove();
    }
  });
});
</script>
```

See [App architecture](https://clayjs.com/docs/guide/architecture/) for structuring delegated commands with undo commits and soft deletes (`clay.trash`).

## Progressive enhancement

Start with plain HTML and layer capabilities one attribute at a time:

```html
<!-- 1. Static HTML -->
<h1>Reading list</h1>

<!-- 2. Editable in the browser -->
<h1 contenteditable="plaintext-only">Reading list</h1>

<!-- 3. Editable in edit mode, saved inert for visitors -->
<h1 editmode:contenteditable inert-contenteditable="plaintext-only">Reading list</h1>
```

Each attribute adds a single behavior while keeping the saved markup clean for visitors.

## State machines in the DOM

Store durable workflow state as attributes on DOM elements and control visibility declaratively with the `clay-options.js` [satellite](https://clayjs.com/docs/satellites/) (`show-when:`, `hide-when:`, `option:`, `option-not:`):

```html
<div id="board" view="cards" onbeforesnapshot="this.setAttribute('view', 'cards')">
  <div show-when:view="cards">Card view</div>
  <div show-when:view="table">Table view</div>
</div>
```

For computed values derived from records, use `clay.effect()` (or [`sap`](https://clayjs.com/docs/plugins/sap/)) to update a [`clay="editor-ui"`](https://clayjs.com/docs/regions/) or `clay="no-dirty"` element whenever the document changes:

```html
<div id="calculator">
  <input type="number" name="price" value="100" persist>
  <input type="number" name="quantity" value="2" persist>
  <div>Total: $<span id="total" clay="no-dirty">200.00</span></div>
</div>

<script>
clay.start(() => {
  const calc = document.getElementById("calculator");
  const total = document.getElementById("total");
  clay.effect(() => {
    const price = parseFloat(calc.querySelector('[name="price"]').value) || 0;
    const quantity = parseFloat(calc.querySelector('[name="quantity"]').value) || 0;
    const next = (price * quantity).toFixed(2);
    if (total.textContent !== next) total.textContent = next;
  });
});
</script>
```

See [App architecture](https://clayjs.com/docs/guide/architecture/) for choosing between saved record attributes, per-tab state (URL hash, `clay.storage`, `ephemeral`), and derived values.

## Single-file philosophy

In a malleable document, everything lives in one HTML file:

- **Markup**: the structure
- **Styles**: the presentation
- **Scripts**: the behavior
- **Record data**: the durable state stored in elements, attributes, text, and `persist` controls
- **Chrome**: the editing interface, hidden from visitors with `show-when:editmode="true"` or mounted at runtime inside `clay="editor-ui"`

The HTML file is at once the source code, the deployed document, the editing environment, and the database. For how to separate records, chrome, and derived values so saves and peer merges stay clean, read [App architecture](https://clayjs.com/docs/guide/architecture/).
