How it works
In a nutshell, Lupus Decoupled Drupal provides an API to fetch data about pages from Drupal by using custom elements. That way the backend may compose pages out of high-level components, while a modern frontend framework like Vue.js may be used for rendering.
What is a custom element?
Custom elements refer to non-standard markup elements, e.g. <flag-icon country="nl">Netherlands</flag-icon>
. They consist of the element name flag-icon
, attributes like country
and contained markup in slots (Netherlands). Slots may contain nested custom elements, markup or just plain text.
For example, this is how a teaser listing using two custom elements, teaser-listing
and article-teaser
could look like:
<teaser-listing title="Latest news" icon="news">
<article-teaser
href="https://example.com/news/1"
excerpt="The excerpt of the news entry."
>
</article-teaser>
<article-teaser
href="https://example.com/news/2"
excerpt="The excerpt of another news entry."
>
</article-teaser>
</teaser-listing>
Providing custom elements
To provide custom elements to the frontend, simply define a route with the format value custom_elements
. The following example lists some teasers using article-teaser
and teaser-listing
from above:
<?php
class NewsController extends ControllerBase {
public function buildNewsListing() {
$articles[] = CustomElement::create('article-teaser')
->setAttribute('href', 'https://example.com/news/1')
->setAttribute('excerpt', 'The excerpt of the news entry.');
$articles[] = CustomElement::create('article-teaser')
->setAttribute('href', 'https://example.com/news/2')
->setAttribute('excerpt', 'The excerpt of another news entry.');
return CustomElement::create('teaser-listing')
->setSlotFromNestedElements('default', $articles);
}
}
This results in the following custom-elements API response, which can serialize the elements either into JSON (default) or markup:
/news
page:
{
"title": "News Listing",
"content_format": "json",
"content": {
"element": "teaser-listing",
"title": "Latest news",
"icon": "news",
"content": [
{
"element": "article-teaser",
"href": "https://example.com/news/1",
"excerpt": "The excerpt of the news entry."
},
{
"element": "article-teaser",
"href": "https://example.com/news/2",
"excerpt": "The excerpt of another news entry."
}
]
}
}
Rendering custom elements
While any frontend framework or tooling may be used to render the custom elements API response, Lupus Decoupled Drupal comes with a ready-to-go Nuxt setup by default, which enables you to get started quickly using Vue.js
So this is how some Vue components for the previous custom elements would look like:
<template>
<article>
<a :href="href">{{ excerpt }}</a>
</article>
</template>
<script setup lang="ts">
const props = defineProps<{
href: string;
excerpt: string;
}>();
</script>
The above example of TeaserListing.vue
assumes that slot content is passed using the JSON serialization of custom elements (default). If you opt for custom elements markup, the <component>
would have to be replaced with a <slot></slot>
. Refer to Render custom elements docs for more details on that.
Support for Drupal content
Note that often, you don't have to code custom routes like this, since Lupus Decoupled Drupal provides custom-elements output for Drupal's content, like associated pages and the various display modes of your content (e.g. a teaser). The custom element output for Drupal's content entities may be configured to suit your frontend components by using its powerful UI and configuration management system.
First steps
Best, test it yourself by either quickly launching a cloud environment or setting up a new project locally, then continue with your first steps.