Ruby on Rails unobtrusive scripting adapter that enables modern JavaScript behaviors through HTML5 data attributes
—
Quality
Pending
Does it follow best practices?
Impact
Pending
No eval scenarios have been run
High-level handlers that implement the core Rails UJS behaviors for method overrides, remote requests, confirmations, and element disabling through HTML data attributes.
Handles confirmation dialogs for elements with data-confirm attributes.
/**
* Handle confirmation dialogs for elements with data-confirm
* @param event - Event that triggered the confirmation (usually click)
*/
function handleConfirm(event: Event): void;
/**
* Show confirmation dialog (overridable)
* @param message - Confirmation message to display
* @param element - Element that triggered the confirmation
* @returns True if user confirmed, false if cancelled
*/
function confirm(message: string, element: Element): boolean;Usage Examples:
<!-- Basic confirmation -->
<a href="/posts/1" data-method="delete" data-confirm="Are you sure?">Delete</a>
<!-- Form confirmation -->
<form action="/posts" method="post" data-confirm="Submit this post?">
<button type="submit">Create</button>
</form>
<!-- Button confirmation -->
<button data-remote="true" data-url="/refresh" data-confirm="Refresh data?">Refresh</button>// Custom confirmation implementation
Rails.confirm = function(message, element) {
return customConfirmDialog(message, {
title: "Please Confirm",
element: element
});
};
// Listen for confirmation events
document.addEventListener("confirm", function(event) {
console.log("Confirming action on:", event.target);
// event.preventDefault() to skip confirmation
});
document.addEventListener("confirm:complete", function(event) {
const [confirmed] = event.detail;
console.log("User decision:", confirmed);
});Handles HTTP method override for links with data-method attributes.
/**
* Handle method override for links with data-method attribute
* @param event - Click event from link with data-method
*/
function handleMethod(event: Event): void;Usage Examples:
<!-- DELETE request via link -->
<a href="/posts/1" data-method="delete">Delete Post</a>
<!-- PUT request with confirmation -->
<a href="/posts/1/publish" data-method="put" data-confirm="Publish this post?">Publish</a>
<!-- PATCH request -->
<a href="/users/1" data-method="patch">Update User</a>// Rails UJS automatically:
// 1. Prevents normal link navigation
// 2. Creates hidden form with correct method
// 3. Includes CSRF token for same-origin requests
// 4. Submits form to trigger server request
// Generated form structure:
// <form method="post" action="/posts/1" style="display: none">
// <input name="_method" value="delete" type="hidden" />
// <input name="authenticity_token" value="..." type="hidden" />
// <input type="submit" />
// </form>Handles AJAX requests for elements with data-remote attributes.
/**
* Handle remote AJAX requests for elements with data-remote
* @param event - Event that triggered the remote request
*/
function handleRemote(event: Event): void;Usage Examples:
<!-- Remote link -->
<a href="/posts/1" data-remote="true">View Post</a>
<!-- Remote form -->
<form action="/posts" method="post" data-remote="true">
<input type="text" name="title">
<button type="submit">Create</button>
</form>
<!-- Remote button -->
<button data-remote="true" data-url="/refresh" data-method="post">Refresh</button>
<!-- Remote with custom data type -->
<a href="/posts.json" data-remote="true" data-type="json">Get JSON</a>// Listen for remote request events
document.addEventListener("ajax:beforeSend", function(event) {
const [xhr, options] = event.detail;
console.log("Making request to:", options.url);
});
document.addEventListener("ajax:success", function(event) {
const [data] = event.detail;
console.log("Remote request succeeded:", data);
});
// Custom handling based on element type
document.addEventListener("ajax:success", function(event) {
if (event.target.matches("form")) {
// Handle form success
showNotification("Form submitted successfully");
} else if (event.target.matches("a")) {
// Handle link success
updatePageContent(event.detail[0]);
}
});Prevents insignificant clicks on links (like meta+click on GET links without data).
/**
* Prevent insignificant clicks from triggering Rails UJS behaviors
* @param event - Click event to potentially prevent
*/
function preventInsignificantClick(event: Event): void;Usage Examples:
// Automatically prevents Rails UJS processing for:
// - Meta+click or Ctrl+click on GET links without data-params
// - Right-click or middle-click on any link
// - This allows normal browser behavior (new tab, context menu, etc.)
// Example scenarios:
// <a href="/posts" data-method="get">Posts</a>
// - Normal click: processed by Rails UJS
// - Meta+click: opens in new tab (Rails UJS skipped)
// <a href="/posts/1" data-method="delete">Delete</a>
// - Meta+click: still processed by Rails UJS (DELETE is significant)CSS selectors used by feature handlers for event delegation.
const linkClickSelector = "a[data-confirm], a[data-method], a[data-remote]:not([disabled]), a[data-disable-with], a[data-disable]";
const buttonClickSelector = {
selector: "button[data-remote], button[data-confirm]:not([form]), button[data-disable-with], button[data-disable]",
exclude: "form button"
};
const inputChangeSelector = "select[data-remote], input[data-remote], textarea[data-remote]";<!-- data-confirm: Message to show in confirmation dialog -->
<a href="/delete" data-confirm="Are you sure you want to delete this?">Delete</a>
<!-- Works with any interactive element -->
<button data-confirm="Clear all data?" onclick="clearData()">Clear</button>
<form data-confirm="Submit form?" action="/submit">...</form><!-- data-method: HTTP method to use instead of GET -->
<a href="/posts/1" data-method="delete">Delete</a>
<a href="/posts/1" data-method="put">Update</a>
<a href="/posts/1" data-method="patch">Patch</a>
<!-- Combines with other attributes -->
<a href="/posts/1"
data-method="delete"
data-confirm="Delete this post?"
data-remote="true">Delete</a><!-- data-remote: Make AJAX request instead of page navigation -->
<a href="/posts/1" data-remote="true">View</a>
<form action="/posts" data-remote="true">...</form>
<!-- data-type: Expected response content type -->
<a href="/data.json" data-remote="true" data-type="json">Get Data</a>
<!-- data-url: URL for button/input requests -->
<button data-remote="true" data-url="/refresh" data-method="post">Refresh</button>
<!-- data-params: Additional parameters -->
<a href="/posts" data-remote="true" data-params="filter=recent">Recent Posts</a>
<!-- data-with-credentials: Include credentials in cross-origin requests -->
<a href="https://api.example.com/data"
data-remote="true"
data-with-credentials="true">External API</a>Rails UJS handlers execute in this order for click events:
All handlers integrate with the Rails UJS event system:
// Before any handler runs
document.addEventListener("ajax:before", function(event) {
// Return false to cancel the action
});
// Confirmation events
document.addEventListener("confirm", function(event) {
// Custom confirmation logic
});
// AJAX events for remote handlers
document.addEventListener("ajax:success", function(event) {
// Handle successful remote requests
});
// Method override events
document.addEventListener("ajax:complete", function(event) {
if (event.target.matches("a[data-method]")) {
// Method override form was submitted
}
});You can add custom handlers using the same delegation pattern:
// Custom handler for special elements
Rails.delegate(document, "[data-custom]", "click", function(event) {
const customValue = this.dataset.custom;
console.log("Custom handler:", customValue);
// Follow Rails UJS patterns
if (!Rails.fire(this, "custom:before", [customValue])) {
return; // Event was cancelled
}
// Your custom logic here
processCustomAction(customValue);
Rails.fire(this, "custom:complete", [customValue]);
});In all handlers, this refers to the element that matched the selector:
Rails.delegate(document, "a[data-method]", "click", function(event) {
// 'this' is the <a> element with data-method
// event.target might be a child element like <span>
const method = this.dataset.method;
const url = Rails.href(this);
});Install with Tessl CLI
npx tessl i tessl/npm-rails--ujs