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:

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

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

This snippet works with both, JSON and markup serialization. The markup serialization uses the slot, while the fallback value of the slot takes care of rendering the JSON-serialized value received as prop.

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:

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

<script setup lang="ts">
defineProps<{
  body?: CustomElementContent;
}>()

Note: When rendering via JSON content, the module supports default components.

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(body)" />
    </slot>
  </div>
</template>

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