Nuxt

Drupal JS libraries

Overview

Drupal emits the JavaScript libraries attached to a rendered form, block or component as <drupal-library-*> custom elements. See Drupal JavaScript for what the backend sends and why; this page covers loading them in Nuxt.

Rendering library elements

Add a global drupal-library--default.vue component - the default component lookup resolves it for every drupal-library-* element, whatever library the backend attached. A reference implementation is part of the playground: drupal-library--default.vue.

The component is renderless: it takes the library, js and drupalSettings props of the element, hands them to useDrupalCe().loadLibrary() on mount, and renders nothing.

<script setup>
const props = defineProps({ js: Array, drupalSettings: String })
const { loadLibrary } = useDrupalCe()

onMounted(() => loadLibrary({ js: props.js, drupalSettings: props.drupalSettings }))
</script>

loadLibrary()

useDrupalCe().loadLibrary(library) takes a resolved library ({ js, drupalSettings }) and returns a promise settling once its files have loaded. On the server it resolves immediately - loading is a client-side concern.

It lazy-loads the actual loader via a dynamic import, so the loader chunk - and the Drupal JavaScript it pulls in - is only fetched by pages that actually render a library element. The loader then:

  • resolves the file URLs against the configured drupalBaseUrl,
  • appends them as <script> tags, preserving execution order across all calls, so libraries load in the dependency order the backend resolved,
  • loads each URL only once, even when several libraries share a file,
  • merges drupalSettings into window.drupalSettings before any script runs,
  • calls Drupal.attachBehaviors() once the batch has loaded, so behaviours attach to the server-rendered markup,
  • skips a file that fails to load with a console warning, rather than aborting the batch.

The attributes a library declares for its <script> tags are currently not applied.

Overriding or skipping a library

To replace a library with a native implementation, add a component named after its element tag - drupal-library-core-drupal-states.vue for core/drupal.states. It takes precedence over the default component, so the library's JavaScript is never loaded. A component that renders nothing and does nothing skips the library entirely.

Trying it out

The playground has a form whose conditional field is driven by core/drupal.states at /form/states, served by a mock Custom Elements API response - a working example of the whole path, from the emitted elements to the attached behaviour.