Now.js Framework Documentation
data-on
data-on
Overview
data-on binds event handlers to elements. It supports event modifiers for common patterns like preventing default behavior, key filtering, and more.
When to use:
- Handle user interactions (clicks, inputs, etc.)
- Respond to keyboard events
- Manage form submissions
Why use it:
- ✅ Declarative event binding
- ✅ 20+ built-in modifiers
- ✅ Automatic cleanup on element removal
- ✅ Supports method arguments
Basic Usage
Click Handler
<button data-on="click:handleClick">Click me</button>In your JavaScript:
function handleClick(event) {
console.log('Button clicked!');
}With Arguments
<button data-on="click:deleteItem(item.id)">Delete</button>function deleteItem(id, event) {
console.log('Delete item:', id);
}Syntax
<element data-on="eventType.modifier1.modifier2:methodName(args)">| Part | Description |
|---|---|
eventType |
DOM event name (click, input, keydown, etc.) |
.modifier |
Optional modifiers (can chain multiple) |
methodName |
Function to call |
(args) |
Optional arguments |
Event Types
All standard DOM events are supported:
| Category | Events |
|---|---|
| Mouse | click, dblclick, mousedown, mouseup, mousemove, mouseenter, mouseleave |
| Keyboard | keydown, keyup, keypress |
| Form | submit, input, change, focus, blur |
| Touch | touchstart, touchend, touchmove |
| Scroll | scroll, wheel |
| Drag | drag, dragstart, dragend, drop |
Modifiers Reference
Event Behavior Modifiers
| Modifier | Description | Equivalent |
|---|---|---|
.prevent |
Prevent default behavior | event.preventDefault() |
.stop |
Stop event propagation | event.stopPropagation() |
.once |
Handle event only once | { once: true } |
.capture |
Use capture phase | { capture: true } |
.self |
Only if target is element itself | event.target === element |
.trusted |
Only trusted events | event.isTrusted |
Key Modifiers
| Modifier | Key |
|---|---|
.enter |
Enter key |
.tab |
Tab key |
.esc |
Escape key |
.space |
Space bar |
Mouse Button Modifiers
| Modifier | Button |
|---|---|
.left |
Left mouse button (button 0) |
.right |
Right mouse button (button 2) |
.middle |
Middle mouse button (button 1) |
System Key Modifiers
| Modifier | Key |
|---|---|
.ctrl |
Control key held |
.alt |
Alt key held |
.shift |
Shift key held |
.meta |
Meta/Command key held |
Features
1. Basic Event Handling
<button data-on="click:save">Save</button>
<input data-on="input:handleInput">
<form data-on="submit:handleSubmit">2. Prevent Default
<!-- Prevent form submission -->
<form data-on="submit.prevent:handleSubmit">
<button type="submit">Submit</button>
</form>
<!-- Prevent link navigation -->
<a href="#" data-on="click.prevent:openModal">Open Modal</a>3. Stop Propagation
<div data-on="click:closeModal">
<div class="modal" data-on="click.stop:noop">
<!-- Click here won't close modal -->
</div>
</div>4. Key Modifiers
<!-- Trigger on Enter key -->
<input data-on="keydown.enter:search">
<!-- Trigger on Escape key -->
<div data-on="keydown.esc:closeModal">
<!-- Trigger on Tab key -->
<input data-on="keydown.tab:moveToNext">5. Modifier Combinations
<!-- Ctrl+Enter to submit -->
<textarea data-on="keydown.ctrl.enter:submit"></textarea>
<!-- Shift+Click -->
<div data-on="click.shift:selectRange"></div>
<!-- Ctrl+S to save -->
<div data-on="keydown.ctrl.s.prevent:save"></div>6. Multiple Event Bindings
<input
data-on="focus:onFocus, blur:onBlur, input:onInput">7. Method Arguments
<!-- Pass data properties -->
<button data-on="click:deleteUser(user.id)">Delete</button>
<!-- Pass literal values -->
<button data-on="click:setStatus('active')">Activate</button>
<!-- Pass multiple arguments -->
<button data-on="click:updateItem(item.id, 'published')">Publish</button>
<!-- Pass index in loop -->
<div data-for="item in items">
<template>
<button data-on="click:selectItem(index)">Select</button>
</template>
</div>8. Self Modifier
<div data-on="click.self:closeSidebar">
<!-- Only triggers when clicking the div itself, not children -->
<button>This click won't trigger closeSidebar</button>
</div>9. Once Modifier
<button data-on="click.once:trackFirstClick">
Click me
</button>Advanced Examples
Form with Validation
<form data-on="submit.prevent:handleSubmit">
<input
type="email"
name="email"
data-on="input:validateEmail, blur:validateEmail">
<input
type="password"
name="password"
data-on="keydown.enter:handleSubmit, input:validatePassword">
<button type="submit">Login</button>
</form>function handleSubmit(event) {
const form = event.target;
// Process form
}
function validateEmail(event) {
const email = event.target.value;
// Validate email
}Keyboard Shortcuts
<div class="editor"
data-on="
keydown.ctrl.s.prevent:save,
keydown.ctrl.z.prevent:undo,
keydown.ctrl.shift.z.prevent:redo,
keydown.esc:closeEditor
">
<textarea data-model="content"></textarea>
</div>Drag and Drop
<div class="dropzone"
data-on="
dragenter.prevent:onDragEnter,
dragover.prevent:onDragOver,
dragleave:onDragLeave,
drop.prevent:onDrop
">
<p>Drop files here</p>
</div>
<div class="draggable"
draggable="true"
data-on="dragstart:onDragStart">
Drag me
</div>Context Menu
<div class="item"
data-on="contextmenu.prevent:showContextMenu">
Right-click for options
</div>Infinite Scroll
<div class="scroll-container"
data-on="scroll:handleScroll">
<div data-for="item in items">
<template>
<div class="item" data-text="item.name"></div>
</template>
</div>
<div data-if="isLoading" class="loader">Loading...</div>
</div>function handleScroll(event) {
const container = event.target;
if (container.scrollTop + container.clientHeight >= container.scrollHeight - 100) {
loadMoreItems();
}
}Interactive List
<ul class="task-list" data-for="task in tasks">
<template>
<li data-class="completed:task.done">
<input
type="checkbox"
data-checked="task.done"
data-on="change:toggleTask(task.id)">
<span data-text="task.title"
data-on="dblclick:editTask(task)"></span>
<button data-on="click.stop:deleteTask(task.id)">×</button>
</li>
</template>
</ul>Touch Events
<div class="swipeable"
data-on="
touchstart:onTouchStart,
touchmove.prevent:onTouchMove,
touchend:onTouchEnd
">
Swipe me
</div>API Reference
Handler Signature
function handlerName(arg1, arg2, ..., event) {
// Arguments passed in data-on come first
// Event object is always the last parameter
}Event Object
The native DOM Event object is passed as the last argument:
| Property | Description |
|---|---|
event.target |
Element that triggered event |
event.currentTarget |
Element with the listener |
event.type |
Event type (click, input, etc.) |
event.key |
Key pressed (for keyboard events) |
event.button |
Mouse button (for mouse events) |
Global vs Component Methods
// Global function
function globalHandler(event) {
console.log('Global handler');
}
window.globalHandler = globalHandler;
// Component method (in component context)
const component = {
methods: {
componentHandler(event) {
console.log('Component handler');
}
}
};Common Pitfalls
⚠️ 1. Function Not Found
<!-- ❌ Function must be global or in component methods -->
<button data-on="click:localFunction">Click</button>
<!-- ✅ Make it global -->
<script>
window.myHandler = function(e) { ... };
</script>
<button data-on="click:myHandler">Click</button>⚠️ 2. Missing Prevent on Forms
<!-- ❌ Form will submit and reload page -->
<form data-on="submit:handleSubmit">
<!-- ✅ Prevent default submission -->
<form data-on="submit.prevent:handleSubmit">⚠️ 3. Event Bubbling Issues
<!-- ❌ Inner click triggers outer handler too -->
<div data-on="click:closeDropdown">
<button data-on="click:toggleDropdown">Toggle</button>
</div>
<!-- ✅ Stop propagation on inner element -->
<div data-on="click:closeDropdown">
<button data-on="click.stop:toggleDropdown">Toggle</button>
</div>⚠️ 4. Button Default Type
Buttons inside forms default to type="submit":
<!-- ❌ This will submit the form -->
<form>
<button data-on="click:doSomething">Click</button>
</form>
<!-- ✅ Explicitly set type -->
<form>
<button type="button" data-on="click:doSomething">Click</button>
</form>Note:
data-onautomatically adds.stopmodifier for clicks on buttons to prevent this issue.
⚠️ 5. Debouncing Rapid Events
// ❌ May fire too often
function handleScroll(e) {
checkInfiniteScroll();
}
// ✅ Throttle/debounce manually
let scrollTimeout;
function handleScroll(e) {
if (!scrollTimeout) {
scrollTimeout = setTimeout(() => {
checkInfiniteScroll();
scrollTimeout = null;
}, 100);
}
}Modifier Combinations Quick Reference
| Pattern | Use Case |
|---|---|
click.prevent |
Links that trigger JS |
submit.prevent |
AJAX form submission |
click.stop |
Prevent bubbling to parent |
keydown.enter.prevent |
Enter submits without newline |
keydown.ctrl.s.prevent |
Custom save shortcut |
click.once |
One-time actions |
click.self |
Only direct clicks |
Related Directives
- data-model - For form input binding
- data-if - For conditional rendering
- data-for - For event handlers in loops