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)" />
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($attrs.body)" />
</slot>
</div>
</template>
<script setup lang="ts">
defineSlots<{
body();
}>()
defineProps<{
title?: string;
}>()
</script>