Drupal Behavior Migration
When to Use
Use this when migrating Drupal behaviors that attach/detach on AJAX swaps. Behaviors work identically with HTMX — the
htmx:drupal:loadandhtmx:drupal:unloadevents triggerDrupal.attachBehaviors()andDrupal.detachBehaviors()automatically.
Decision
| What changes | What stays the same |
|---|---|
jQuery.once() → once() API |
attach / detach structure |
$('.class', context) → once('id', '.class', context) |
trigger === 'unload' check |
| jQuery wrapping | context parameter as swapped element |
Pattern
BEFORE:
(function ($, Drupal, once) {
Drupal.behaviors.myContent = {
attach: function (context, settings) {
$('.ajax-content', context).once('my-content').each(function() {
$(this).data('plugin', new MyPlugin(this));
});
},
detach: function (context, settings, trigger) {
if (trigger === 'unload') {
$('.ajax-content', context).each(function() {
var plugin = $(this).data('plugin');
if (plugin) plugin.destroy();
});
}
}
};
})(jQuery, Drupal, once);
AFTER:
(function (Drupal, once) {
Drupal.behaviors.myContent = {
attach: function (context, settings) {
// context is the HTMX-swapped element
once('my-content', '.ajax-content', context).forEach(function(el) {
el.myPlugin = new MyPlugin(el);
});
},
detach: function (context, settings, trigger) {
if (trigger === 'unload') {
once.remove('my-content', '.ajax-content', context).forEach(function(el) {
if (el.myPlugin) el.myPlugin.destroy();
});
}
}
};
})(Drupal, once);
Common Mistakes
- Thinking behaviors need changes → They do not. Behaviors work the same with HTMX. The
contextparameter is the swapped element - Not using
once()API → Modern Drupal uses theonce()function, not jQuery.once(). Update to the new API - Expecting different trigger values → HTMX uses the same
triggervalues:'unload'when content is removed,'serialize'before submit - Removing jQuery too aggressively → If your behavior uses jQuery internally, that is fine. Only the
onceAPI must be native - Not testing detach →
htmx:drupal:unloadfires before swap. Verify your cleanup actually runs
See Also
- Previous: Custom AJAX Command Migration
- Next: Accessibility Migration
- Reference: Drupal once API
- Source:
/core/misc/htmx/htmx-behaviors.js