Rendering Custom Elements

The Drupal Custom Elements Connector module allows you to render custom elements in your Nuxt.js application fetched from a Drupal backend.

Basics

Generally, each custom element maps to a Vue component, which is automatically picked up when the component is named exactly like the custom element, e.g. for the element drupal-markup create the component drupal-markup.vue.

There is one gotcha though: For Vue to find your custom element components, they must be globally registered. Thus, in Nuxt, simply put them into your components/global folder, and they are picked up.

Mapping attributes to props

Every attribute of a component is available in Vue's $attrs variable. However, it's best practice to define the props for the component, what makes each attribute available under its defined name:

<template>
  <div class="node">
    <h2 v-if="title">Node: {{ title }}</h2>
  </div>
</template>

<script setup lang="ts">
defineProps<{
  title?: string;
}>()
</script>

Rendering slots

Rendering slots works differently depending on whether custom-elements are serialized into JSON or markup. In short, for rendering a slot in a Vue template, simply use the following snippet:

<slot name="body">
  <component :is="useDrupalCe().renderCustomElements($attrs.body)" />
</slot>

This snippet works with both, JSON and markup serialization.

JSON serialization (default)

Custom elements contained in slots get passed as JSON, which can be easily rendered with the helper provided by the nuxtjs-drupal-ce connector:

      <component :is="useDrupalCe().renderCustomElements($attrs.body)" />

Markup serialization

With markup, the Vue template compiler needs to be enabled:

// nuxt.config.js
export default {
  vue: {
    runtimeCompiler: true
  }
}

Then, slots will be directly passed as Vue slots.

  <slot name="body">Fallback content.</slot>

Full example

Here is an example of a component that leverages props and slots and works with both markup and JSON serialization:

<template>
  <div class="node">
    <h2 v-if="title">Node: {{ title }}</h2>
    <slot name="body">
      <component :is="useDrupalCe().renderCustomElements($attrs.body)" />
    </slot>
  </div>
</template>

<script setup lang="ts">
defineSlots<{
  body();
}>()
defineProps<{
  title?: string;
}>()
</script>