Skip to content

JavaScript Development

I need to... Guide Summary
Understand Drupal's JavaScript architecture JavaScript Architecture Understand how Drupal loads and manages JavaScript before implementing any JS functionality. Core pattern: libraries define assets, behaviors initialize them, once() prevents duplicate processing.
Define a JavaScript library Library Definitions Every JS addition to a module or theme must be defined in a library. Core pattern: MODULE.libraries.yml with js:, dependencies:, and optional css:/version:/attributes:. Gotcha: missing core/drupal or core/once breaks behaviors and once() respectively.
Choose core dependencies Core Dependencies When defining any JavaScript library, declare exactly what your code needs so Drupal loads dependencies automatically. Gotcha: including jQuery when not needed adds ~30KB unnecessarily.
Load scripts in header or footer Header vs Footer Loading Load JavaScript in the footer by default; only use the header for JS that must execute before page render. Gotcha: header: true is a library-level key, a sibling of js: and version:, not a per-file option.
Attach libraries via PHP Library Attachment Methods Choose where to attach a library via #attached based on scope: global (hooks), form-specific (form arrays), template-specific (preprocess), or element-specific (render elements). Gotcha: drupal_add_js() was removed in Drupal 8+.
Load JavaScript conditionally Conditional Loading Evaluate conditions in PHP before attaching libraries, and declare cache contexts so conditional libraries work with page caching. Gotcha: checking conditions in JavaScript instead of PHP defeats the optimization since the JS is already loaded.
Initialize JavaScript on page load and AJAX Drupal.behaviors Pattern Always use Drupal.behaviors for DOM manipulation, since $(document).ready() only runs once and breaks with AJAX and BigPipe. Gotcha: skip the once() wrapper or context parameter and behaviors re-scan the whole DOM or double-bind on every AJAX update.
Prevent duplicate initialization Once API Wrap every element you process in a behavior with once() so it runs exactly once even when the behavior re-executes on AJAX updates. Gotcha: once() writes a single data-once attribute holding a space-separated id list, not a per-id attribute.
Pass PHP data to JavaScript drupalSettings Use drupalSettings to pass server-side data to JavaScript available at page render, as an alternative to an AJAX request. Gotcha: never pass sensitive data — it's visible in page source.
Manipulate the DOM safely DOM Manipulation Prefer vanilla JavaScript (querySelector, addEventListener, classList) over jQuery for DOM manipulation; jQuery stays acceptable for existing jQuery-heavy code or complex traversal. Gotcha: never use innerHTML with unsanitized user input.
Choose between HTMX and legacy AJAX AJAX Integration Understand the landscape of dynamic content loading in Drupal: HTMX (Drupal 11.3+) is the modern declarative path, the legacy AJAX API is imperative and required for Drupal 10.x or existing systems. Gotcha: both work automatically with Drupal.behaviors via context — no manual re-init needed.
Handle user interactions and events Event Handling Use vanilla addEventListener for user interactions, event delegation for dynamic content, and debounce/throttle for performance-intensive events, with keyboard handling for accessibility. Gotcha: no debounce on scroll/resize/input executes hundreds of times per second and freezes the UI.
Use ES6+ features ES Modules and Modern JavaScript Understand modern JavaScript features available in Drupal 10/11: ES6+ syntax works directly in .js files with no build process, since Drupal 10 dropped IE11 support. Gotcha: import/export statements are not fully supported in Drupal's library system yet.
Add JavaScript to SDC components JavaScript in SDC Components Place a JavaScript file in the component directory following naming convention, and Drupal creates the library and attaches it automatically when the component renders. Gotcha: the auto-generated library name is core/components.THEME_OR_MODULE--COMPONENT, not sdc/...
Optimize JavaScript performance Performance Optimization Minimize JavaScript weight, load conditionally, use defer, implement debounce/throttle, and avoid layout thrashing on every implementation — performance is not optional. Gotcha: reading layout properties in a loop forces multiple reflows.
Enable aggregation and minification Aggregation and Minification Always enable JavaScript aggregation in production — Drupal aggregates files into a single bundle, minifies, and serves with far-future cache headers. Gotcha: always test with aggregation enabled before deployment, since it works in dev and can break in production.
Use defer and async attributes Defer and Async Attributes Use defer for most JavaScript — it downloads in parallel and executes in order after DOM ready; use async only for independent scripts where execution order doesn't matter. Gotcha: aggregation may remove defer, so test the configuration.
Debounce or throttle events Debounce and Throttle For events that fire rapidly (scroll, resize, input, mousemove), use Drupal's built-in debounce to execute after events stop, or throttle to cap execution rate. Gotcha: requestAnimationFrame suits visual updates better than throttle since it syncs with refresh rate.
Prevent XSS and secure JavaScript Security Sanitize all user input before inserting into the DOM, use Drupal.checkPlain() for escaping, and never pass sensitive data through drupalSettings. Gotcha: never use innerHTML with unsanitized data, and avoid eval() or new Function() — both break CSP.
Test JavaScript functionality Testing JavaScript Use Nightwatch.js — which replaced PHPUnit's FunctionalJavascriptTestBase — to verify JavaScript functionality in real browsers via WebDriver, especially AJAX interactions and accessibility. Gotcha: accessibility testing uses .axeInject() and .axeRun(), not .initAccessibility()/.assert.accessibility().
Avoid common mistakes Common Anti-Patterns Review these eight anti-patterns when checking JavaScript code — each includes the WRONG and CORRECT form plus why it matters. Gotcha: an anti-pattern often works initially but fails with AJAX, caching, or scale.
Review code quality standards Best Practices Summary Senior-developer review questions and a development standards checklist covering architecture, performance, security, and modern-pattern requirements for Drupal JavaScript.