Core Concepts
Understanding these fundamental concepts will help you think in Hyperclay and build more effective HTML apps.
DOM as Database
In traditional web apps, data lives in a separate database. In Hyperclay, the DOM itself is your database.
Traditional approach:
// Data in JavaScript
let tasks = [{id: 1, text: "Buy milk", done: false}];
// Sync to DOM
function renderTasks() {
tasksContainer.innerHTML = tasks.map(t =>
`<div>${t.text}</div>`
).join('');
}
Hyperclay approach:
<!-- Data lives directly in the DOM -->
<div class="task" data-done="false">Buy milk</div>
The DOM element is the single source of truth. No synchronization needed.
Self-Modifying Documents
Hyperclay documents can modify and save themselves. This isn’t just editing contentit’s the document rewriting its own source code.
How it works:
- User interacts with the page
- JavaScript modifies the DOM
- Save captures the entire DOM state
- The modified HTML becomes the new document
Example self-modification:
<button onclick="this.nearest.section.after(this.nearest.section.cloneNode(true));">Add Section</button>
When saved, the new section becomes part of the permanent document.
View vs Edit Mode
Every Hyperclay document operates in two distinct modes:
View Mode
- Default state for all visitors
- Interactive but read-only
- No editing controls visible
- Forms and buttons work normally
Edit Mode
- Available only to document owners
- Editing controls appear
- Elements become modifiable
- Save functionality enabled
Mode-specific elements:
<!-- Only visible in edit mode -->
<button option:editmode="true" trigger-save>Save Changes</button>
<!-- Editable only in edit mode -->
<h1 edit-mode-contenteditable>Page Title</h1>
Save-Strip-Restore Cycle
The three-phase cycle that enables clean separation between editing and viewing:
1. Save Phase
When you trigger save:
onbeforesave
callbacks fire for cleanup- Elements with
edit-mode-resource
are removed - Attributes prefixed with
edit-mode-
are stripped - The cleaned DOM is serialized to HTML
2. Strip Phase
The server stores the cleaned HTML:
- No editing interfaces remain
- No admin-only code exists
- Just the pure application
3. Restore Phase
When an editor loads the page:
- Edit permissions are detected
edit-mode-
attributes are re-enabled- Hidden admin interfaces appear
- Save functionality activates
Locality of Concern
Unlike traditional web development that separates HTML, CSS, and JavaScript into different files, Hyperclay embraces localitykeeping related code together.
Everything in one place:
<div class="counter">
<style>
.counter {
border: 1px solid #ccc;
padding: 20px;
text-align: center;
}
</style>
<h3>Counter: <span>0</span></h3>
<button onclick="this.previousElementSibling.querySelector('span').textContent++">
Increment
</button>
</div>
Structure, styling, and behavior unite in a single, understandable unit.
Template-Clone Pattern
Create dynamic lists by cloning template elements rather than generating HTML strings.
Template element (hidden):
<ul id="tasks">
<!-- First child is the template -->
<li class="task hidden" onclone="this.classList.remove('hidden')">
<input type="checkbox" persist>
<span contenteditable>New task</span>
<button onclick="this.nearest.task.remove()">Delete</button>
</li>
</ul>
Add button:
<button onclick="this.nearest.task.after(this.nearest.task.cloneNode(true));">Add Task</button>
The template provides structure. Cloning creates instances. The DOM is the component system.
Event Delegation
Since content can be added dynamically, use event delegation to handle events on future elements:
<script>
// Attach to parent, not individual elements
document.addEventListener('click', e => {
// Complete task
if (e.target.matches('.task-complete')) {
e.target.closest('.task').dataset.status = 'done';
}
// Delete task
if (e.target.matches('.task-delete')) {
e.target.closest('.task').remove();
}
});
</script>
New elements automatically inherit behavior based on their classes and position in the DOM.
Don’t be afraid to inline code
Hyperclay resurrects inline event handlers and styles as primary patterns:
Inline events:
<button onclick="this.textContent = 'Clicked!'">Click me</button>
<input oninput="this.nextElementSibling.textContent = this.value">
<select onchange="document.body.className = this.value">
Inline Tailwind classes:
<script edit-mode-resource="" src="https://hyperclay.com/js/vendor/tailwind-play.js"></script>
<div class="text-xl bg-slate-200 mb-8">Styled inline for immediate understanding</div>
When everything is visible at the point of use, there’s no need to hunt through files to understand behavior.
Progressive Enhancement
Start simple, add complexity only when needed:
<!-- Level 1: Basic HTML -->
<h1>My App</h1>
<!-- Level 2: Make it editable -->
<h1 contenteditable>My App</h1>
<!-- Level 3: Only editable for owners -->
<h1 edit-mode-contenteditable>My App</h1>
Each attribute adds one specific capability. Build up functionality incrementally.
Single File Philosophy
Everything lives in one HTML file:
- Markup: The structure
- Styles: The appearance
- Scripts: The behavior
- Data: The state
- Editor: The development environment
When everything is in one place, you can understand the entire application at once. No hidden dependencies. No configuration files. No build process.
Your HTML file is simultaneously:
- The source code
- The deployed application
- The development environment
- The data storage