HTMX with Hyperscript — Complete Guide with Examples
In this tutorial, you'll learn about combining HTMX with Hyperscript. We cover key concepts, practical examples, and best practices to help you understand and apply this topic effectively.
Hyperscript is a scripting language for HTMX that lets you add client-side behavior, event handling, and logic directly in HTML without writing JavaScript, complementing HTMX's server-driven approach.
What You'll Learn
By the end of this tutorial, you'll install Hyperscript, handle events, manipulate the DOM, set values, use control flow, and combine Hyperscript with HTMX attributes for rich client-side behavior.
Why It Matters
HTMX excels at server communication but needs a partner for client-side logic: showing/hiding elements, animating, validating forms before submit, or responding to events. Hyperscript fills this gap without a separate JavaScript file.
Real-World Use
Doda Browser's HTMX-powered settings page uses Hyperscript for client-side validation before form submission, animated UI transitions, and coordinating complex multi-step interactions that would otherwise require custom JavaScript.
Where This Fits in Your Learning Path
flowchart LR
A["Indicators & UX"] --> B["**Hyperscript**"]
B --> C["HTMX Extensions"]
C --> D["HTMX Project"]
D --> E["Advanced HTMX"]
style B fill:#3b82f6,stroke:#2563eb,color:#fff
style A fill:#e2e8f0,stroke:#94a3b8
style E fill:#e2e8f0,stroke:#94a3b8
Installing Hyperscript
Add the Hyperscript script tag after HTMX.
<script src="https://cdn.jsdelivr.net/npm/htmx.org@2.x.x/dist/htmx.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/hyperscript.org@0.x.x/dist/_hyperscript.min.js"></script>
Basic Event Handling
Use the _ (underscore) attribute for Hyperscript code.
<button _="on click toggle .highlight on #content">
Toggle Highlight
</button>
<div id="content">
This div gets highlighted on click
</div>
<style>.highlight { background: #ffeb3b; padding: 8px; border-radius: 4px; }</style>
Expected output: Clicking the button toggles the highlight class on the content div.
Combined HTMX and Hyperscript
Trigger HTMX requests and run Hyperscript simultaneously.
<button hx-post="/api/submit"
hx-target="#result"
_="on htmx:afterRequest
if event.detail.successful
add .success to #result
else
add .error to #result">
Submit
</button>
<div id="result"></div>
<style>
.success { border-left: 4px solid #4ecdc4; }
.error { border-left: 4px solid #ff6b6b; }
</style>
Expected output: After the HTMX request completes, Hyperscript adds a success or error class to the result div based on the response.
Form Validation with Hyperscript
Validate form fields before HTMX submission.
<form hx-post="/api/register"
hx-target="#form-result"
_="on submit
if #email.value is not *@*
halt the default
put 'Invalid email' into #form-result
end
if #name.value is empty
halt the default
put 'Name is required' into #form-result
end">
<input id="name" name="name" placeholder="Name">
<input id="email" name="email" type="email" placeholder="Email">
<button type="submit">Register</button>
</form>
<div id="form-result"></div>
Expected output: The form validates before submission. Invalid inputs show error messages without sending the request.
DOM Manipulation
Hyperscript can add, remove, and toggle elements.
<div _="on click
add .active to me
set my innerHTML to 'Clicked!'">
Click me
</div>
<button _="on click
put 'New Item' at end of #list
add .item to last child of #list">
Add Item
</button>
<ul id="list"></ul>
Expected output: Clicking the first div changes its content. Clicking the button appends items to the list.
Control Flow and Conditions
Hyperscript supports if/else, loops, and wait.
<button _="on click
set count to 0
repeat 5 times
increment count
put count into #counter
wait 500ms
end
put 'Done!' into #counter">
Start Count
</button>
<div id="counter">0</div>
Expected output: Clicking the button counts from 1 to 5 with 500ms intervals, then shows "Done!".
Common Mistakes
1. Forgetting the Hyperscript script tag
Hyperscript code silently fails if the library isn't loaded. Check the browser console for errors.
2. Using Hyperscript for complex state management
Hyperscript handles simple logic well. For complex client-side state, use Alpine.js alongside HTMX.
3. Mixing Hyperscript and JavaScript event handlers
Hyperscript syntax differs from JavaScript. Don't mix _="on click" with onclick="" on the same element.
4. Not using quotes properly in Hyperscript
String values need double quotes inside the attribute: _='on click put "hello" into #output'.
5. Creating infinite loops without wait
Hyperscript loops without wait or break can freeze the browser. Always include a termination condition.
Practice Questions
What attribute does Hyperscript use? The
_(underscore) attribute on any HTML element.How do you handle a click event in Hyperscript?
_="on click doSomething".How do you set an element's text content?
put 'text' into #elementId.Can Hyperscript listen to HTMX events? Yes. Use
on htmx:afterRequestor other HTMX events.How do you prevent default behavior in Hyperscript? Use
halt the defaultinside an event handler.
Challenge
Build a multi-step form that uses HTMX for server validation on each step and Hyperscript for client-side navigation between steps, progress indication, and field validation.
FAQ
Mini Project
Build an interactive dashboard with HTMX and Hyperscript. HTMX handles data fetching and updates. Hyperscript handles tab switching, notification toasts, and animated counters.
<div _="on htmx:afterRequest from #dashboard
if event.detail.successful
put 'Updated at ' + new Date().toLocaleTimeString() into #update-time
add .flash to #dashboard
wait 500ms
remove .flash from #dashboard
end">
<div id="update-time">Last updated: never</div>
<div hx-get="/api/dashboard/data"
hx-trigger="every 30s"
hx-target="#dashboard"
hx-indicator="#loader"
id="dashboard">
Dashboard content
</div>
<button hx-get="/api/dashboard/data"
hx-target="#dashboard"
_="on click
add .loading to me
wait until no .htmx-request from #dashboard
remove .loading from me">
<span class="htmx-indicator" id="loader">Refreshing...</span>
<span _="on load from #dashboard put 'Refresh' into me">Refresh</span>
</button>
<style>
.flash { animation: flash 0.5s ease-out; }
@keyframes flash { 0% { background: rgba(59,130,246,0.2); } 100% { background: transparent; } }
.loading { opacity: 0.6; pointer-events: none; }
</style>
</div>
What's Next
Extend HTMX with extensions:
| Tutorial | What You'll Learn |
|---|---|
| HTMX Extensions | Use community HTMX extensions for advanced features |
| HTMX Project | Build a complete production-ready HTMX application |
Related topics: event-driven programming, declarative vs imperative programming.
Built by the developers of DodaTech
Doda Browser, DodaZIP & Durga Antivirus Pro