Custom elements
Introduction
The Custom Elements module provides the framework for rendering Drupal data (entities, fields, ...) into custom elements markup. Custom elements can be easily rendered by frontend components, e.g. via web components or various Javascript frontend frameworks. This enables Drupal to render into high-level theme components, while the actually rendering of the components is handled by a frontend application (possibly in the browser).
The Custom Elements module provides
- the API to build a (nested tree) of custom element objects, with associated cache metadata
- the API to serialize a tree of custom objects into markup or into a JSON representation
- the API for other modules to customize how data is rendered into custom elements via Custom element processors
Frontend rendering
Today's browsers provide an API
for developers to define their own HTML elements, like
<flag-icon country="nl"></flag-icon>
. Besides that, many frontend frameworks
render their components using the same, or similar custom elements syntax.
That way, we can render a custom element with Web components or suiting frontend
frameworks, like Vue.js.
Usage
Progressive decoupling
Custom elements output may be used as part of a regular Drupal-rendered
response, where some JavaScript or Web-Components take over the rendering in
the browser. For that use case any Javascript libraries needed for rendering the
markup maybe added to the custom_elements/main
library, e.g. in a custom
theme. This library is attached to every custom element markup rendered via
Drupal.
Full decoupling
Alternatively, the module can be used in conjunction via the Lupus Custom Elements Renderer modules or Lupus Decoupled Drupal. The Lupus Custom Elements Renderer modules switches Drupal's main content renderer to provide API responses using custom elements markup or a custom elements JSON serialization for complete pages.
Note: When used together with a module like "Lupus CE Renderer" entities are rendered via custom elements by default - it's not necessary to take-over rendering an entity-view into custom elements.
Lupus Decoupled Drupal builds upon Lupus Custom Elements Renderer and packages it up into an easily usable decoupled setup, see https://lupus-decoupled.org
Configuration
By default, the modules does nothing unless it's API is used by other modules (e.g. the Lupus CE renderer) or it's configured to take over entity rendering for some entity view modes. When an entity-view is rendered with custom elements, the entity is rendered into custom-elements this way:
- When layout builder is enabled for the view-mode, it's applied and the layout
is rendered into custom elements. It does so by rendering them into
<layout-section>
elements and allows the contained blocks to render into custom elements. - When there is a custom-elements display-config for the entity, it's applied. The display is configured to use custom-element field formatter plugins to render individual fields. See "Custom element displays" for more details.
- The display config has a config-only option "forceAutoProcessing" which disables the per-field component configuration. Instead, it applies automatic processing via processor services to the entity-level, as it was default in version 2.x and is the same as the "auto" CE-field formatter does on field level. For backwards compatibility with 2.x, this config options may be enabled. See "Automatic rendering with processors" for more information below.
The custom elements UI sub-module may be enabled to configure the custom-elements display config via UI.
Custom element render formats
The module supports two main serialization modes:
- Markup - Render custom elements into HTML-like markup.
- JSON - Render a JSON tree representation of custom elements.
The markup variant supports multiple styles to cater for the different needs of different frameworks.
Custom Element markup styles
Custom elements use "slots" for handling content distribution, i.e. for passing nested content to an element. However, the concrete syntax used for handling slots may differ by various frameworks. Thus, the module supports rendering to different markup styles while it defaults to the Web component style syntax, which is supported by Vue 2 as well (via its legacy slot syntax). In addition, the module supports the Vue2 and Vue 3 syntax which can be enabled via config:
drush config:set custom_elements.settings markup_style vue-3
Further details
Automatic rendering with processors
The module comes with Custom element processors that try to implement
a reasonable default for content entities. These defaults can be further
customized with custom modules as suiting, as shown by the included
custom_elements_thunder
example module of version 2.x.
In automatic mode, the module renders the data of all visible fields either as attribute to the custom element tag, or as nested markup via a slot. The module maps simple fields and their properties to attributes and falls back to rendering more complex fields to regular markup, which gets added as slot to the parent custom element.
Custom element displays
The default processor that renders a whole entity, makes use of "Custom element
displays". When the custom_elements_ui
module is enabled, these can be
configured next to the "Manage display" option for Drupal's regular displays
for entity bundles / view modes. There are some subtleties in when/how these
displays are applied, when an entity is being rendered:
-
If an entity is rendered by Drupal's standard pipeline (e.g. as part of a list of node teasers), custom elements only becomes active if Drupal's regular display for the specified (or default) view mode has the "Force rendering as custom element" enabled.
-
When not using layout builder, custom elements renders a certain entity using a display specific to the entity type/bundle, similarly to Drupal's standard pipeline:
- If a custom elements display is available/enabled for the specified view mode, then it is used.
- Otherwise, if a 'default' custom elements display is enabled, then it is used.
- If the custom element display has "forceAutoProcessing" enabled, the automatic rendering via custom element processors kicks in as it was default in 2.x: For that Drupal's regular display (for the specified view mode or default) is taken as a basis: all enabled fields are rendered, with a processor being automatically selected for each field (i.e. like the "Auto" option in a custom elements display).
- When no custom element entity-display config is available, a config with reasonable defaults is auto-generated and applied.
Upgrade from 2.x
Preparation
Make sure some submodules are not enabled, or deal with uninstalling the nonexistent modules later: (They have been removed as of the first 3.x release because of their very small install base.)
-
custom_elements_everywhere: There is no 100% replacement; all entities/bundles can have Custom Elements enabled in the corresponding "Manage display" tab in the UI. (In terms of configuration: in each applicable core.entity_view_display.TYPE.BUNDLE.VIEWMODE configuration entity, set third_party_settings.custom_elements.enabled = true.)
-
custom_elements_thunder: It's been decided to ship v3 without any of the processors that were present in this submodule. All these processors applied to a content type or paragraph type; it should be possible to replace these with Custom Elements Displays that are now shipped with the module. The output is not always 100% the same, but it should be close enough that it should be easy to update your frontend (if even needed) to accommodate some renamed properties. If you really need to keep the processors, check https://www.drupal.org/i/3443424.
-
custom_elements_thunder: It's been decided to ship 3.x without any of the processors that were present in this submodule in 8.x-2.x. All these processors applied to a paragraph type; it should be possible to replace these with Custom Elements Displays that are now shipped with the submodule. See the module's README.md.
Update
TODO re-document this (when the checkbox is there): By default custom-element display config is applied. If that's not desired, regular displays can be still used by enabling "forceAutoProcessing" in the respective entity-ce-display. That way, the automatic-rendering via processors is applied again as it was default in 2.x.
Caveat / edge case: disabled view modes
It is technically possible to 'build' (using processors in 2.x) content using a view mode that does not exist - or at least, one that is not enabled. If you are doing this and your default view mode is set up to use Layout Builder, then v3 will render content in not-enabled view modes using Custom Elements + Layout Builder, instead of just Custom Elements (i.e. take the processor with the highest priority for the entity) like 2.x did.
The only way around this is to create/enable (core's view) Display Modes for the applicable bundles + view modes, which have Layout Builder disabled. Then also create a Custom Element display (and configure it, or set it to fall back to 2.x behavior).
Credits
- drunomics GmbH: Concept, Development, Maintenance
- Österreichischer Wirtschaftsverlag GmbH: Initial sponsor of v1