[{"data":1,"prerenderedAt":468},["ShallowReactive",2],{"search-api":3},[4,11,25,35,43,51,60,70,78,87,97,105,115,123,131,144,156,167,177,185,194,202,210,221,230,238,246,252,264,275,285,293,301,308,315,322,329,342,350,360,368,377,387,398,408,418,428,436,446,455],{"id":5,"path":6,"dir":7,"title":8,"description":7,"keywords":9,"body":10},"content:0.index.md","/","","Lupus Decoupled Drupal",[],"     The power of Drupal,    with a modern frontend   Enjoy component-oriented Decoupled Drupal with   Nuxt  and   Vue.js     A complete, fully integrated solution - working   out of the box !  Drupal powered editorial control of pages, layouts, paths, metatags, breadcrumbs and previews  Leverage   Drupal authentication  in the frontend. Edit buttons and Drupal messages just work!  Performance focused, integrates well with Drupal page caching!  Multi-Frontend: Works with any frontend, while defaulting to Nuxt  Low-code: Configure Drupal API output, no PHP-coding required!    Main features      The power of Drupal   Build versatile, structured content. Incredible tools, proudly open source!    Fully integrated   Authentication and edit links in the frontend, simply working previews in the backend.    Multi-frontend   Component-oriented decoupled Drupal makes it easy to connect your frontend of choice!    Nuxt default frontend   Web development intuitive and powerful. With the power of Vue Components   (more)    Low-code   Configure Drupal-API output and allow editors to compose pages with the Drupal Canvas visual page builder.    Easy deployment   Leverage Nuxt deployment presets or deploy everything at a unified hosting provider.",{"id":12,"path":13,"dir":14,"title":15,"description":16,"keywords":17,"body":24},"content:1.get-started:10.how-it-works.md","/get-started/how-it-works","get-started","How it works","In short, Lupus Decoupled Drupal bridges the gap between your Drupal backend and modern frontend frameworks, giving you the flexibility to leverage\nthe power of Drupal while using a modern framework for rendering. It does that by providing an API for fetching page-data from Drupal, utilizing custom elements to compose pages from high-level components.",[18,19,20,21,22,23],"What is a custom element?","Providing custom elements","Custom Elements Page-API","The frontend","Rendering custom elements","First steps","  How it works  In short, Lupus Decoupled Drupal bridges the gap between your Drupal backend and modern frontend frameworks, giving you the flexibility to leverage\nthe power of Drupal while using a modern framework for rendering. It does that by providing an API for fetching page-data from Drupal, utilizing custom elements to compose pages from high-level components.  What is a custom element?  Custom elements refer to non-standard markup elements, commonly used for components in frontend frameworks. For example:\n  \u003Cflag-icon country=\"nl\">Netherlands\u003C/flag-icon> . Custom elements consist of:    Element name  -   flag-icon   Attributes : such as   country   Slots : which can contain:\n    Nested custom elements   Markup  or    Plain text  For example, this is how a teaser listing using two custom elements,   teaser-listing  and   article-teaser  could look like:     \u003C  teaser-listing   title  =  \"Latest news\"   icon  =  \"news\"  >\n       \u003C  article-teaser\n           href  =  \"https://example.com/news/1\"\n           excerpt  =  \"The excerpt of the news entry.\"\n       >\n       \u003C/  article-teaser  >\n       \u003C  article-teaser\n           href  =  \"https://example.com/news/2\"\n           excerpt  =  \"The excerpt of another news entry.\"\n       >\n       \u003C/  article-teaser  >\n   \u003C/  teaser-listing  >\n  Providing custom elements  While custom elements can be easily created in a custom Drupal route   with code , the most common needs can be served by utilizing the Drupal UI to configure the API output. Lupus Decoupled Drupal already provides custom elements output for the main routes of all content entities and allows customizing it via UI, see   Customized API output .  Custom Elements Page-API  Lupus Decoupled Drupal introduces the   /ce-api/\u003Croute>  Drupal API endpoint, which takes care of rendering a regular Drupal request into a custom-elements API response. So Drupal paths like   /node/1  or   /news  would be served by the API as pages rendered with custom element at   /ce-api/node/1  and   /ce-api/news .  This endpoint results in the following custom-elements API response, which can serialize the elements either into JSON (default) or markup. For example, the API output of a   /news  page outputting the previous example custom elements would be:      {\n   \n       \"title\"  :   \"News Listing\"  ,\n       \"content_format\"  :   \"json\"  ,\n       \"content\"  : {\n             \"element\"  :   \"teaser-listing\"  ,\n             \"props\"  : {\n                   \"title\"  :   \"Latest news\"  ,\n                   \"icon\"  :   \"news\"\n             },\n             \"slots\"  : {\n                   \"default\"  : [\n                         {\n                               \"element\"  :   \"article-teaser\"  ,\n                               \"props\"  : {\n                                     \"href\"  :   \"https://example.com/news/1\"  ,\n                                     \"excerpt\"  :   \"The excerpt of the news entry.\"\n                               }\n                         },\n                         {\n                               \"element\"  :   \"article-teaser\"  ,\n                               \"props\"  : {\n                                     \"href\"  :   \"https://example.com/news/2\"  ,\n                                     \"excerpt\"  :   \"The excerpt of another news entry.\"\n                               }\n                         }\n                   ]\n             }\n       },\n       \"messages\"  : [ ],\n       \"breadcrumbs\"  : [ ],\n       \"metatags\"  : {\n         \"meta\"  : [\n           {\n             \"name\"  :   \"title\"  ,\n             \"content\"  :   \"Drupal powered metatags\"\n           }\n         ],\n         \"link\"  : [\n           {\n             \"rel\"  :   \"canonical\"  ,\n             \"href\"  :   \"https://example.com/\"\n           }\n         ]\n       }\n   }\n     {\n       \"title\"  :   \"News Listing\"  ,\n       \"content_format\"  :   \"markup\"  ,\n       \"content\"  :   \"\n         \u003Cteaser-listing title=  \\\"  Latest news  \\\"   icon=  \\\"  news  \\\"  >\n           \u003Carticle-teaser to=  \\\"  https://example.com/news/1  \\\"   excerpt=  \\\"  The excerpt of the news entry.  \\\"   slot=  \\\"  default  \\\"  >\u003C/article-teaser>\n           \u003Carticle-teaser to=  \\\"  https://example.com/news/2  \\\"   excerpt=  \\\"  The excerpt of another news entry.  \\\"   slot=  \\\"  default  \\\"  >\u003C/article-teaser>\n         \u003C/teaser-listing>\"  ,\n       \"messages\"  : [ ],\n       \"breadcrumbs\"  : [ ],\n       \"metatags\"  : {\n         \"meta\"  : [\n           {\n             \"name\"  :   \"title\"  ,\n             \"content\"  :   \"Drupal powered metatags\"\n           }\n         ],\n         \"link\"  : [\n           {\n             \"rel\"  :   \"canonical\"  ,\n             \"href\"  :   \"https://example.com/\"\n           }\n         ]\n       }\n   }\n  The frontend  The frontend typically proxies requests to the Drupal   /ce-api  endpoint, while preserving the request URI and optionally some request headers.\nThat way, a request to   /news  is served by the frontend, which requests the backend API at   /ce-api/news  and takes care\nof rendering the response. By forwarding the cookie header, the frontend may easily leverage Drupal   authentication handling .  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. This enables you to get started quickly using   Vue    Single-File-Components , which implements a template and web-standard oriented approach.  Rendering custom elements  Generally, each custom element maps to a Vue component, which is automatically picked up for rendering, when the component is named exactly like the custom element. For example, for the element   article-teaser  create the component   ArticleTeaser.vue .  The following example shows how Vue components for the previous custom elements could look like:      \u003C  template  >\n     \u003C  div   class  =  \"teaser-listing\"  >\n       \u003C  h2  >Title: {{ title }}\u003C/  h2  >\n       \u003C  slot   /  >\n     \u003C/  div  >\n   \u003C/  template  >\n   \n   \u003C  script   setup   lang  =  \"ts\"  >\n     defineProps  \u003C{\n       title  :   string  ;\n     }>();\n   \u003C/  script  >\n     \u003C  template  >\n     \u003C  div   class  =  \"article-teaser\"  >\n       \u003C  a   :  href  =  \"  href  \"  >{{  excerpt }}\u003C/  a  >\n     \u003C/  div  >\n   \u003C/  template  >\n   \n   \u003C  script   setup   lang  =  \"ts\"  >\n     defineProps  \u003C{\n       href  :   string  ;\n       excerpt  :   string  ;\n     }>();\n   \u003C/  script  >\n  The above example of   TeaserListing.vue  makes use of native Vue slots to render the article teasers. With JSON-based rendering (the default), the Nuxt Drupal CE connector automatically handles slot content - simply use   \u003Cslot />  in your template and it works out of the box. Markup-based rendering requires additional setup and configuration. Refer to   Render custom elements  docs for more details.  First steps  Best, test things yourself by either quickly launching a   cloud environment  or setting up a   new project  locally, then continue with your   first steps .  html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}",{"id":26,"path":27,"dir":14,"title":28,"description":7,"keywords":29,"body":34},"content:1.get-started:20.play-online.md","/get-started/play-online","Play online",[30,31,32,33],"About GitHub Codespaces","Quick Start with Preconfigured Codespaces","How to Use It?","What’s Included in the Setup?","  Play online  About GitHub Codespaces   GitHub Codespaces  is a cloud-based development environment integrated with\nGitHub, allowing you to develop directly within your browser. Github Codespaces\nprovides 120 hours and 15 GB/month storage for   free ! This allows you to explore\n  Lupus Decoupled Drupal  without a local setup.  Quick Start with Preconfigured Codespaces  Choose one of the following preconfigured development environments based on\nyour needs (clicking on a link launches that Codespace):    Drupal 11 + Nuxt Naked Starter   Drupal 11 + Nuxt with shadcn/ui components   Drupal 11 + Next.js frontend  How to Use It?   Click on the link for your desired configuration.  GitHub will automatically create a new Codespace with the selected setup.  Wait for the container to initialize—this may take a few minutes.  Once ready, the development environment is fully set up and running in your browser.  In the   ports  tab there are links to the running services.\n   Frontend is available by clicking the link next to port 3000.  Backend is at port 80. By default it redirects to frontend. To prevent redirect visit the /user/login path of backend URL.  The environment may take a few minutes to initialize. Once you are up and running, try adding some content nodes and\nmenu items to see it working . Then continue with your   first steps  What’s Included in the Setup?   A fully configured development container, with both Drupal and a frontend.  Automatic port forwarding for running services.  Development setup based upon ddev.",{"id":36,"path":37,"dir":14,"title":38,"description":7,"keywords":39,"body":42},"content:1.get-started:30.create-new-project.md","/get-started/create-new-project","Create a new project",[40,41],"Local setup with ddev","Custom setup","  Create a new project  Local setup with ddev  For setting up a new project, you may want to use the   lupus-decoupled-project  template, which supports both   cloud environments \nand local docker-based development environments via   DDEV .  Prerequisites: ddev & docker  ddev is a ridiculously simple setup for complex development environments, based upon docker compose.  Requirements:   ddev v1.23 or later. Please follow the   installation instructions  Launch it  To spin up the project locally run:     git   clone   git@github.com:drunomics/lupus-decoupled-project.git\n   cd   lupus-decoupled-project\n   ddev   start\n   ddev   composer   install\n   ddev   drush   site-install   -y   --account-pass=admin   --site-name=  'lupus_decoupled'   standard\n   ddev   drush   pm-enable   lupus_decoupled,   services_env_parameter   -y\n   # Configure lupus-decoupled frontend base URL\n   ddev   drush   config:set   lupus_decoupled_ce_api.settings   frontend_base_url   https://lupus-nuxt.ddev.site   -y\n   # Login and get started adding some test-nodes\n   ddev   drush   user-login\n  When using ddev locally, the URLs are by default:   Frontend:   https://lupus-nuxt.ddev.site  Backend:   https://lupus-decoupled.ddev.site/admin  Once you are up and running, try adding some content nodes and menu items to see it working and continue with your   first steps  ddev configuration  URLs  If you want to customize URLs, take a look at the   .ddev/config.yaml  file and re-run   ddev start .  Frontend repository  By default, the naked   nuxt-starter  frontend repository is used. It can be customized by setting the   FRONTEND_REPOSITORY  via ddev config:     # Configure a different frontend repository.\n   ddev   config   --web-environment-add=  \"FRONTEND_REPOSITORY=https://github.com/drunomics/lupus-decoupled-nuxt-shadcn\"\n  Resources    .ddev/config.yaml  - main ddev (default) configuration, can be generated by running   ddev config   ddev docs  Custom setup  If preferred, you can incorporate the pieces in your custom setup and/or setup everything from scratch by following the next steps.  Setting up Drupal  If you don't have an existing Drupal installation yet, or you want to start from scratch,\ninstall Drupal first:     composer   create-project   drupal/recommended-project   drupal-project\n   cd   drupal-project\n  If you do not have composer installed, see the official   composer installation instructions .  Continue with the Drupal installation, e.g. by using Drupal's quick start command:     php   ./web/core/scripts/drupal   quick-start   standard\n  The quick-start command uses PHP's built-in webserver to run your site. Just keep it running after installation.  If you prefer a full local development setup based upon docker, check the\n  Local development guide .  Add   drush  - the Drupal cli:     composer   require   drush/drush\n   # If no global drush launcher is already in use, run\n   alias   drush  =  $PWD/vendor/bin/drush\n  Adding Lupus Decoupled Drupal  The   Lupus Custom Elements renderer module  lets Drupal provide\nan API backend rendering custom elements. Add the module and its dependencies, then enable the module\nvia the UI or if installed, via   drush .     composer   require   drupal/lupus_decoupled\n   drush   en   lupus_decoupled   -y\n   drush   user-login\n  Test your installation by opening   http://127.0.0.1:8888/ce-api/  - when logged in,\nyou should see a JSON response with the following   content  property:     \u003C  drupal-markup  >Welcome to your custom-elements enabled Drupal site!\u003C/  drupal-markup  >\n  Setting up Nuxt      npx   nuxi@latest   init   \u003C  project-nam  e  >\n     pnpm   dlx   nuxi@latest   init   \u003C  project-nam  e  >\n  Answer the questions as preferred, generally the defaults work fine.\nOnce the project is created, you can remove the example components.  For further details, please refer to the   official Nuxt installation docs .  Adding the Nuxt connector module  Please refer to the   Setup steps  then continue below.  Run nuxt  Ready to go! Start testing by running Nuxt in development mode:      npm   run   dev\n     yarn   dev\n     pnpm   dev\n  Now, when accessing the nuxt dev server (e.g. at   http://localhost:3000/ )\nyou should see a naked page rendered, having the \"Home\" breadcrumb\nand the message shown to logged-out users on the frontpage:\n\"You are not authorized to access this page.\"  Connecting the dots  In your Drupal backend, set the URL of your frontend site, either via UI or via console:     drush   config:set   lupus_decoupled_ce_api.settings   frontend_base_url   http://localhost:3000   -y\n  html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}",{"id":44,"path":45,"dir":14,"title":23,"description":46,"keywords":47,"body":50},"content:1.get-started:40.first-steps.md","/get-started/first-steps","This page provides a short playbook which introduces you to the most important features of Lupus Decoupled Drupal. It only takes 1-2 minutes to follow:",[48,49],"Creating and viewing content","Inspecting API output of content","  First steps  This page provides a short playbook which introduces you to the most important features of Lupus Decoupled Drupal. It only takes 1-2 minutes to follow:  Creating and viewing content   Create an article\nIn the backend, login and go to   /node/add/article  to create some first example content.  Fill in some random content and save it.  After saving, you are redirected to the frontend, which renders the basic data of your content. You can customize that easily, as described under the   Customized API output  page. For now, stay here and remember the frontend URL of your page, e.g.   /node/1 .  On the frontend go the user login, e.g.   /user/login?destination=/ . Login with your usual Drupal credentials, e.g. as admin or editor account. For the Gitpod demo environments you can log in with   admin  and password   lupus123 .  After logging in, go back to your created content in the frontend, e.g.   /node/1 . Take note of the local task links (or \"Drupal-tabs\") that appear now.  Click the   Edit  task link, to get back to the Drupal edit page. Now, let's change the   URL-alias  of the content in the right sidebar, e.g. to   /example-path . Also, in the sidebar, enable the option to provide a menu item and keep the defaults.  Save the form and take note of the changes appearing in the frontend:   The URL of the content changed to   /example-path .  A menu items is appearing in the main menu, which is part of the site header.  A success message is provided by Drupal and shown in the frontend.  Optionally, you may log out in the frontend, separate from the backend, by visiting the   /user/logout  path in the frontend.  Inspecting API output of content   After creating content, it's listed in Drupal's content management screen at   /admin/content/node  in the backend.  To inspect the custom element API output of some content, use the drop-down next to the   Edit  operation button on the right and choose the entry   API output . It shows the API output of the associated page.  Optionally, switch between markup and JSON serialization by appending the query parameter   ?_content_format=markup  or   ?_content_format=json  (default) to the URL of the API output.  Continue with   customizing the API output .",{"id":52,"path":53,"dir":54,"title":55,"description":56,"keywords":57,"body":59},"content:2.guide:05.customized-api-output.md","/guide/customized-api-output","guide","Customized API Output","Lupus Decoupled Drupal provides custom elements output for all content entities. This includes the page of a content node (\"Full content\"), just as the individual view-modes that may be used in content listings, e.g. teasers (Drupal allows the configuration of any number of view-modes).",[58],"Custom Element Display Configuration","  Customized API Output  Lupus Decoupled Drupal provides custom elements output for all content entities. This includes the page of a content node (\"Full content\"), just as the individual view-modes that may be used in content listings, e.g. teasers (Drupal allows the configuration of any number of view-modes).  A content entity can be rendered into custom elements via three methods, while the method used can be configured by view-mode. For example, when editing a content type at   admin/structure/types  go to the tab \"Manage custom element\" to configure your method.   Note : This requires the Custom Elements UI submodule, make sure it is enabled.  The three methods are:   Custom Element Display Configuration - The typically used default method. It allows fine-grained control of the output via UI. Please see below for more details.  Layout builder - When enabling the \"Layout Builder\" module for a view-mode, the layout builder may be used to allow editors to compose pages that are displayed using custom elements. Refer to the   Layout Builder guide  for details. Activate it by ticking the \"Use Layout Builder\" checkbox in the UI; this checkbox is visible only after a layout is enabled through \"Manage display\".  Automatic processing (advanced) - A method that allows taking full control of the output via PHP code, as outlined   here . Activate it by ticking the \"Automatic processing\" checkbox in the UI.  Custom Element Display Configuration  For each view-mode, the display configuration may be used to configure the   name  of the custom element used. Next, for each content field the data may be mapped to a slot or property with a configurable name:   For each field various options are available:    Auto  - Provides a reasonable default based upon   automatic processing  of the field.   Raw  - Provides the raw Drupal field data.   Flattened  - Instead of containing a nested object for individual data properties of a field, the output is flattened and each property gets added to the main element, prefixed by the property name. For example, a field with the data properties   value  and   format  would get flattened to   foo-value  and   foo-format  attributes, when the name   foo  is configured. Note that for fields containing multiple values, only the first value is output and flattened.   Formatted - ... : Every Drupal field formatter rendering a field into HTML is available.   Custom element - Rendered entity : This is available only for entity reference fields. It's a powerful way to configure the rendering of the referenced data. The display of the selected entity and view-mode can be configured via its own \"Custom Element Display Configuration\". That way the output data of referenced entities can be controlled in high detail. Furthermore, by enabling the \"Flatten\" option the data may be flattened into the main element.  Note that the list of available options is plugin-based, and thus extendable by Drupal modules.",{"id":61,"path":62,"dir":54,"title":63,"description":64,"keywords":65,"body":69},"content:2.guide:10.pages-routing.md","/guide/pages-routing","Pages & Routing","By default, the frontend forwards all page requests to Drupal. Given that, Drupal's routes, URL aliases as well as 404 or 403 pages all work out of the box. However, the frontend may add custom routes in front of Drupal's routing, see \"Custom routes in the frontend\".",[66,67,68],"Configure error page and frontpage","URL Aliases","Custom routes in the frontend","  Pages & Routing  By default, the frontend forwards all page requests to Drupal. Given that, Drupal's routes, URL aliases as well as 404 or 403 pages all work out of the box. However, the frontend may add custom routes in front of Drupal's routing, see \"Custom routes in the frontend\".  Configure error page and frontpage  The default pages (front, 403, and 404) are configured in the Drupal admin UI under:   Administration  >   Configuration  >   System  >   Site information  URL Aliases  URL aliases are configured in the Drupal admin UI and just work. Configure them at:   Administration  >   Configuration  >   Search and metadata  >   URL aliases  Custom routes in the frontend  The frontend can also define custom routes. When the frontend defines a custom route, it takes priority and works as usual. When no custom route is defined, the frontend default route forwards requests to Drupal and Drupal's routing takes effect.  For more information on defining custom routes with nuxt, please see the   Custom routes  section.",{"id":71,"path":72,"dir":54,"title":73,"description":7,"keywords":74,"body":77},"content:2.guide:20.site-layout-menus.md","/guide/site-layout-menus","Site layout & Menus",[75,76],"Site layout","Navigation menus","  Site layout & Menus  Site layout  By default, Lupus Decoupled Drupal only serves the main page content as part of its page API response. That way, the overall site layout may be custom-built in the frontend, while some dynamic elements like navigation menus are fetched from Drupal using separate API requests.   Thanks to client-side navigation, the header and footer does not need to be re-fetched for subsequent pages.  That means, by default, the Drupal \"Block layout\" configuration is ignored and not applied. By installing the \"Lupus Decoupled Drupal - Blocks\" submodule, support for that configuration may be enabled. Please refer to   Advanced Topics > Block layout  for more details on that.  Finally, it's possible to swap the used site-layout for some pages, e.g. by changing the value of the \"layout\" attribute for the page API responses. Please refer to   Nuxt > Page Layouts  for more details on that.  Navigation menus  Lupus Decoupled Drupal integrates with the   Rest menu items  module.\nThat module is automatically installed and configured as part of Lupus Decoupled Drupal, so the REST API endpoints providing the Drupal menu items (see /admin/structure/menu) are available under   https://yourdrupalsite.com/ce-api/api/menu_items/{menu_name} .  Combined with the default menu components provided by the Nuxt Drupal CE Connector modules, the main menu works out of the box, while additional menus may be fetched and displayed the same way.",{"id":79,"path":80,"dir":54,"title":81,"description":82,"keywords":83,"body":86},"content:2.guide:40.authentication.md","/guide/authentication","Authentication","Since page requests are processed by Drupal as usual, Drupal's authentication and session handling\nstays fully working. Thus, when requests provide an authentication cookie, authentication just works. By default, cookie-based authentication with a separate frontend cookie is used.",[84,85],"Cookie-based authentication","OAuth / OpenID Connect","  Authentication  Since page requests are processed by Drupal as usual, Drupal's authentication and session handling\nstays fully working. Thus, when requests provide an authentication cookie, authentication just works. By default, cookie-based authentication with a separate frontend cookie is used.  Cookie-based authentication  Cookie-based authentication can be achieved in one of the following three ways:  1. Separate frontend cookie  This is the default configured of the provided project template. The Nuxt Drupal CE Connector module forwards the cookie of every request. Thus, when a user logs in on the frontend domain, the set-cookie header is also forwarded and a cookie gets set on the frontend domain and thus is applied automatically.  The login on the frontend works via the regular Drupal login form when the \"Lupus Decoupled User Form\" is enabled. Simply visit   /user/login?destination=/  on the frontend to access it.  That way, the frontend login works with the same user accounts as the backend, but uses a separate session. The frontend and the backend needs a separate login. Also, since this variant requires a server, it only works in a server-rendered frontend setup.  2. Shared cookie domain  The Nuxt Drupal CE Connector module makes sure to forward a received cookie to the backend, such that authenticated requests just work. Instead of having a separate frontend cookie, Drupal may be configured to set the cookie on a shared, parent cookie domain. For example   drupal.example.com  and   nuxt.example.com  can both use the cookie on   .example.com .  The Drupal cookie domain is configured via its   services.yml  file. Besides that, the project template supports setting the cookie domain via an environment variable, please refer to its   README  for further details.  3. CORS setup  When the JavaScript application sends requests directly to Drupal, it's possible to leverage cookie-based authentication when configuring CORS appropriately. Lupus Decoupled Drupal comes with a CORS submodule which takes care of the necessary setup. However, browser privacy features may intervene and not send the cookie to another domain reliably in some cases.  OAuth / OpenID Connect  Drupal provides great support for OAuth based login flows via the   Simple OAuth  extension module. A frontend may use it to authenticate all or some requests with it. For example, it might be useful for authenticating requests to a protected API that is called from the frontend server.",{"id":88,"path":89,"dir":54,"title":90,"description":91,"keywords":92,"body":96},"content:2.guide:50.metatags-local-tasks.md","/guide/metatags-local-tasks","Metatags & Local tasks","Lupus Decoupled Drupal integrates with the Drupal Metatags module and local tasks (Drupal tabs) and provides them as part of the API response.",[93,94,95],"Metatags","Schema.org via JSON-LD","Local tasks","  Metatags & Local tasks  Lupus Decoupled Drupal integrates with the Drupal Metatags module and local tasks (Drupal tabs) and provides them as part of the API response.  The   Nuxt CE connector  has that functionality built-in, such that metatags, link relations and local tasks work out of the box.  Metatags  The frontend can access the metatags via the   metatags  property of the API response.  The metatags are grouped by their group name, e.g.   meta  or   jsonld . Each group contains an array of metatags.  Example API output:     \"metatags\"  : {\n     \"meta\"  : [\n       {\n         \"name\"  :   \"title\"  ,\n         \"content\"  :   \"Lupus Decoupled Drupal\"\n       },\n       {\n         \"name\"  :   \"description\"  ,\n         \"content\"  :   \"Lupus Decoupled Drupal\"\n       },\n       {\n         \"property\"  :   \"og:url\"  ,\n         \"content\"  :   \"https://lupus-decoupled.org\"\n       },\n     ],\n     \"link\"  : [\n       {\n         \"rel\"  :   \"canonical\"  ,\n         \"href\"  :   \"https://lupus-decoupled.org\"\n       }\n     ]\n   },\n  The metatags can be configured by visiting:   Administration  >   Configuration  >   Search and metadata  >   Metatag  Schema.org via JSON-LD  The   Schema.org  structured data markup is supported via the Drupal extension module   Schema Metatag . When installed, the structured data can be configured through the Metatag module's user interface. The data is output in the API response under the   jsonld  metatag group. On the frontend, the Nuxt Drupal-CE connector supports outputting JSON-LD and handles it automatically.  Local tasks  The frontend can access the local tasks via the   local_tasks  property of the API response.  The local tasks are grouped by their primary and secondary tabs.  Example API output:     \"local_tasks\"  : {\n     \"primary\"  : [\n       {\n         \"url\"  :   \"/frontpage\"  ,\n         \"label\"  :   \"View\"  ,\n         \"active\"  :   true\n       },\n       {\n         \"url\"  :   \"/node/1/edit\"  ,\n         \"label\"  :   \"Edit\"  ,\n         \"active\"  :   false\n       },\n       {\n         \"url\"  :   \"/node/1/delete\"  ,\n         \"label\"  :   \"Delete\"  ,\n         \"active\"  :   false\n       },\n       {\n         \"url\"  :   \"/node/1/layout\"  ,\n         \"label\"  :   \"Layout\"  ,\n         \"active\"  :   false\n       },\n       {\n         \"url\"  :   \"/node/1/revisions\"  ,\n         \"label\"  :   \"Revisions\"  ,\n         \"active\"  :   false\n       },\n       {\n         \"url\"  :   \"/entity_clone/node/11\"  ,\n         \"label\"  :   \"Clone\"  ,\n         \"active\"  :   false\n       },\n     ],\n     \"secondary\"  : []\n   }\n  html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}",{"id":98,"path":99,"dir":54,"title":100,"description":7,"keywords":101,"body":104},"content:2.guide:60.breadcrumbs-messages.md","/guide/breadcrumbs-messages","Breadcrumbs & Messages",[102,103],"Breadcrumbs","Messages","  Breadcrumbs & Messages  Breadcrumbs  The Lupus custom elements renderer module integrates with Drupal's breadcrumb handling and simply provides the breadcrumbs generated by Drupal as part of its API response.\nCombined with the default components provided by the Nuxt Drupal CE Connector module, the breadcrumbs are output as generated by default.  Drupal breadcrumbs may be customized using Drupal's API or by installing some contributed\nmodule that provide UI for doing so, for example   Easy breadcrumb .  Messages  The Lupus custom elements renderer module integrates with Drupal's message handling\nand simply provides Drupal messages as part of its API response. Combined with the\ndefault components provided by the Nuxt Drupal CE Connector modules, Drupal messages are displayed automatically.  Messages with static site generation  When a redirect points to a statically pre-generated page, there is no API request made for the static page. For a message to be displayed, the message must be sent with the redirect response (unlike with the next page response, which is the Drupal default).  Messages with server renderings  For server-rendering, messages need to be sent with the subsequent page response. If sent with the redirect response, a message is only displayed when the redirect response is handled by a client-side API request. To fix this for server-rendered redirect responses, please see   this issue .",{"id":106,"path":107,"dir":54,"title":108,"description":109,"keywords":110,"body":114},"content:2.guide:65.redirects.md","/guide/redirects","Redirects","Lupus Decoupled Drupal supports CMS-controlled redirects, i.e. Drupal's page API explicitly informs the frontend\nabout redirects to be generated. The frontend, in turn, simply generates the right redirect responses. That way,\nDrupal-managed redirects just work in the decoupled frontend.",[111,112,113],"Redirect API responses","Managing redirects via UI","Creating redirects via code","  Redirects  Lupus Decoupled Drupal supports CMS-controlled redirects, i.e. Drupal's page API explicitly informs the frontend\nabout redirects to be generated. The frontend, in turn, simply generates the right redirect responses. That way,\nDrupal-managed redirects just work in the decoupled frontend.  Redirect API responses  The Drupal   page API  may return data about the page to render OR alternatively\na redirect response. A redirect response is formatted like this:     {\n         \"redirect\"  : {\n               \"external\"  :   false  ,\n               \"url\"  :   \"/new-path\"  ,\n               \"statusCode\"  :   301\n         },\n         \"messages\"  : [ ]\n   }\n  In the above example, the frontend would return a HTTP 301 redirect to   /new-path  when the path   /some-redirect-path \nis requested.  Managing redirects via UI  The Drupal   Redirect module  provides the ability to create manual redirects and maintains a canonical URL for all content, redirecting all other requests to that path. To use the module with Lupus Decoupled Drupal, simply install and use it - it just works.  Creating redirects via code  Drupal modules may programmatically create redirect responses. To do so, simply return a regular redirect response\nobject from the route, the Lupus CE Renderer module is taking care of converting it to a redirect JSON\nresponse when the custom-elements format is requested automatically.  html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}",{"id":116,"path":117,"dir":54,"title":118,"description":7,"keywords":119,"body":122},"content:2.guide:70.editorial-previews.md","/guide/editorial-previews","Editorial previews",[120,121],"Content previews","Responsive preview","  Editorial previews  Content previews  When editing a content node, Drupal displays a preview button. The Lupus custom elements renderer module supports rendering preview routes, so previews of content nodes work fine. For improving this preview with a back button, please refer to   this issue .  Responsive preview  Lupus Decoupled Drupal integrates with the Drupal   responsive preview module . After installing the extension module, simply enable the provided \"Lupus Decoupled Responsive Preview\" module.  When the module is setup, the responsive preview widget in the Drupal admin toolbar may be used on the content node edit form to open the preview in a modal dialog.",{"id":124,"path":125,"dir":54,"title":126,"description":7,"keywords":127,"body":130},"content:2.guide:80.layout-builder.md","/guide/layout-builder","Layout builder",[128,129],"Rendering layouts","Layout previews","  Layout builder    Consider using   Drupal Canvas  instead.  Canvas is Drupal's modern page builder and supersedes Layout Builder for most decoupled use cases. Layout Builder remains supported but Canvas is recommended for new projects.  The Drupal   layout builder  module may be leveraged for customizing the page layout per entity or content type within Drupal. Optionally, this default may be customized by each individual content item. That way, the module can be used as a custom page builder tool.  Rendering layouts  By default, layouts are rendered using a   \u003Cdrupal-layout>  custom element for each layout section, such that any section settings are forwarded to the frontend. Contained blocks may build their content using custom elements, or fallback to Drupal rendering and regular HTML.  Please see   Drupal > Providing blocks  for more details on how to provide Drupal blocks that render custom elements.  Layout previews  Lupus Decoupled Drupal provides a route for previewing layouts in the frontend, i.e.   node/XX/layout-preview . For providing a nice UX to open the preview, the integration with the responsive preview module is leveraged (see   editorial previews ). The responsive preview widget in the Drupal admin toolbar may be used on the layout builder page to open the preview in a modal dialog. Additionally, a link to open a full-page preview in a new tab is provided.",{"id":132,"path":133,"dir":54,"title":134,"description":135,"keywords":136,"body":143},"content:2.guide:90.canvas.md","/guide/canvas","Drupal Canvas","Drupal Canvas is Drupal's modern page builder (docs). When paired with Lupus Decoupled, Canvas becomes a powerful decoupled page builder that supports varying frontend frameworks.",[137,138,139,140,141,142],"How It Works","Drupal CMS","Manual Setup","Providing Components","Component Registration","Relationship to Canvas Code Components","  Decoupling Drupal Canvas   Drupal Canvas  is Drupal's modern page builder (  docs ). When paired with Lupus Decoupled, Canvas becomes a powerful decoupled page builder that supports varying frontend frameworks.  How It Works  Canvas pages are built from components in Drupal's Canvas editor. In this context, a component can be a custom element (a Vue/React component provided by the frontend) or a regular Drupal block — which can render any Drupal content, including Views blocks that themselves output custom elements. While editing, the editor renders live previews of components via JavaScript using a preview provider (i.e. the frontend). Once published, the page is served through the CE API like any other content (e.g.   /ce-api/page/{id} ), as regular   custom elements API  output, so components are regularly rendered by the frontend.  Drupal CMS  When using   Lupus Decoupled Starter  or a similar site template based upon Lupus Decoupled, you get a fully working setup with Canvas pre-configured. Refer to the   Drupal CMS page  for details.  Manual Setup  Apply the   Lupus Decoupled Canvas Recipe  to set up the module and its dependencies with a single recipe apply:     composer   require   drupal/lupus_decoupled_recipe_canvas\n   drush   recipe   ../recipes/lupus_decoupled_recipe_canvas\n  This installs and configures   Canvas ,   Canvas ExtJS , and the Lupus Decoupled Canvas sub-module.  Configuring the Editor Theme  Configure the theme used for Canvas editor previews at   /admin/config/system/lupus-decoupled/settings  under \"Lupus Decoupled theme\". A minimal theme like Stark or   Lupus Stark  is recommended.  Providing Components  Components are provided via a   component index : a JSON file listing available components, their props, and metadata.   Canvas External JS Components  (a Canvas extension for integrating external JavaScript components) reads this index and makes the components available in the Canvas editor UI.    Vue/Nuxt : very well supported via   nuxt-component-preview , see   Component Previews  React: no ready-made setup yet.   fullfatthings/drupal-canvas-react  provides a library for exposing React components and generating a component index, but some integration work is required to wire everything together.  For documentation on how to integrate other frontend frameworks, see   Multi-Frontend .  Component Registration  Automatic Registration via Lupus CSR Themes  When a Lupus CSR-based theme is installed, components are automatically registered from the theme's bundled component-index. No manual steps are needed.  Automatic registration also works with a decoupled frontend when the   lupus_decoupled_canvas  module is installed, provided the configured frontend exposes a component index at the configured frontend base URL.  Decoupled Frontends  When using a decoupled frontend (e.g. a dev server), component registration must be triggered manually:    UI : Go to   Administration > Appearance > Components > External JS  (  /admin/appearance/component/extjs )   Drush :   drush canvas:extjs-auto-register   Recipe config action : Use   lupus_decoupled_canvas:registerComponents  after configuring the preview provider URL  When the frontend base URL is changed via the Lupus Decoupled settings form, a prompt will remind you to update the component registration.  Relationship to Canvas Code Components  Drupal Canvas has built-in support for (P)React \"code components\" with their own bundler. These components are purely client-side rendered and currently do not integrate with Lupus Decoupled's CE API pipeline. Adding support for embedding them as custom elements would be straightforward, but is not implemented yet.  html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}",{"id":145,"path":146,"dir":54,"title":138,"description":147,"keywords":148,"body":155},"content:2.guide:95.drupal-cms.md","/guide/drupal-cms","Drupal CMS is Drupal's user-friendly distribution aimed at marketers and content teams. Lupus Decoupled supports it via site templates, providing a fully decoupled setup out of the box.",[149,150,151,152,153,154],"Installation","First Steps","Client-Side Rendering (CSR)","Customizing the Theme","Switching to Server-Side Rendering","Creating New Site Templates","  Drupal CMS with Lupus Decoupled   Drupal CMS  is Drupal's user-friendly distribution aimed at marketers and content teams. Lupus Decoupled supports it via site templates, providing a fully decoupled setup out of the box.  The   Lupus Decoupled Starter  is a ready-to-use Drupal CMS site template that bundles:    Drupal CMS base setup : content types, editorial workflow, and other Drupal CMS defaults   Lupus Decoupled Recipe : core modules and configuration   Lupus Decoupled Canvas : Canvas visual editor integration   Lupus CSR : client-side rendering theme with the   Nuxt Starter  (set as default)  Installation  Install the starter as a site template when setting up Drupal CMS, or apply it manually:     composer   require   drupal/lupus_decoupled_starter\n   drush   site-install   ../recipes/lupus_decoupled_starter\n  For a full local setup with DDEV:     mkdir   my-drupal-site   &&   cd   my-drupal-site\n   ddev   config   --project-type=drupal11   --docroot=web\n   ddev   composer   create-project   drupal/cms\n   ddev   composer   require   drupal/lupus_decoupled_starter\n   drush   site-install   ../recipes/lupus_decoupled_starter\n   ddev   launch\n  First Steps  After installation, navigate to   Content > Pages  in the Drupal admin to find the provided demo content. Open a page, review it, and try editing it with the Canvas visual page builder to get familiar with the setup.  Client-Side Rendering (CSR)  The starter uses   Lupus CSR  (Client-Side Rendering) as the default theme. This means:   The frontend is pre-built and served directly from Drupal, with no separate frontend server needed  The frontend JavaScript runs in the browser and fetches content from the CE API at   /ce-api/...  on the same origin, so no CORS configuration is required  This is ideal for getting started quickly, but   not recommended for SEO-critical production sites  (use SSR instead)  All Lupus Decoupled documentation applies regardless of whether you use CSR or SSR. For Nuxt rendering mode details, see   Rendering modes .  Customizing the Theme  To customize the frontend, run a local frontend dev server and point Drupal to it during development:   Go to   Configuration → Lupus Decoupled Settings  (  /admin/config/services/lupus-decoupled )  Set   Frontend base URL  to your dev server and enable frontend redirects  Pages and Canvas previews now render via the dev server. When adding new Canvas components or changing their props, go to   Administration > Appearance > Components > External JS  (  /admin/appearance/component/extjs ) and press   Update components .  Provide an Updated Lupus CSR Theme  Once customization is done, generate a production build of your frontend and configure Lupus CSR to serve it via   /admin/appearance/settings/lupus_csr . For sub-theme packaging, see   Creating a Sub-Theme .  For detailed instructions for the Nuxt-based default theme, see   CUSTOMIZING.md .  Switching to Server-Side Rendering  To move from CSR to SSR:   Set up a separate frontend server  Configure the Lupus Decoupled frontend URL to point to your frontend server and enable the frontend redirect  Refer to   Deployment strategies  for options.  Creating New Site Templates  The Lupus Decoupled Starter is designed to serve as a template for building new Drupal CMS site templates. See the   Site Templates  page for guidance.  html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}",{"id":157,"path":158,"dir":159,"title":160,"description":161,"keywords":162,"body":166},"content:3.advanced-topics:05.multi-frontend.md","/advanced-topics/multi-frontend","advanced-topics","Multi-frontend","Thanks to the component-oriented decoupling of Lupus Decoupled Drupal, it's really easy to connect a frontend of choice!",[163,164,165],"Supported frontend frameworks","Example frontends","Adding a new frontend framework","  Multi-frontend  Thanks to the component-oriented decoupling of Lupus Decoupled Drupal, it's really easy to connect a frontend of choice!  Supported frontend frameworks  Lupus Decoupled provides supports for the following frontend frameworks:     Framework  Technology  Status  Description  Link     Nuxt  Vue.js, JavaScript  Default, Stable & Complete   Easy setup  via re-usable connector module.   Connector module    Next.js  React, JavaScript  Proof-of-concept  Example implementation, see README for details.   Example implementation   Yours?   Add it!     Example frontends    Nuxt Naked Starter   Nuxt Shadcn Example   Next.js Example   Nuxt 2 Example (legacy)  Adding a new frontend framework  Adding a support for a new framework is quite easy. Here is a short overview of what the frontend needs to take care of:    Proxying requests : The frontend typically proxies requests to the Drupal   /ce-api  endpoint, while preserving the request URI and optionally some request headers.\nThat way, a request to   /news  is served by the frontend, which requests the backend API at   /ce-api/news  and takes care\nof rendering the response.   Forwarding headers : By forwarding the cookie header, the frontend may easily leverage Drupal   authentication handling .   Rendering page content : The   content  section of a response contains a nested tree of custom elements that need to be rendered on the page.   Render a page shell : Request   navigation menus  and render them as part of a   site layout .   Support page attributes : Support all page attributes provided by the Drupal   page API , i.e. render   breadcrumbs and messages , support   Metatags and Local tasks .   Handle errors : Take care to not add special handling for HTTP 4xx responses, such that Drupal-controlled error pages get rendered as usual. Simply take care of forwarding the status code.   Handle redirects : When the page-API generates a   redirect response  instead of a page, take care to issue a suitable redirect response with the given status code instead of rendering a page.   Canvas support  (optional): To support   Drupal Canvas , two additional pieces are needed:\n    Custom Elements preview provider : Implement a preview provider plugin so the Canvas editor can render live component previews via an iframe. The provider receives a component name and props and renders the component in isolation. See the   Nuxt preview provider plugin  as a reference implementation.   Component index : Expose a   component-index.json  endpoint listing available components, their props, and metadata.   Canvas External JS Components  (a Canvas extension for integrating external JavaScript components) reads this index to populate the Canvas editor UI. See the   nuxt-component-preview component index  and   fullfatthings/drupal-canvas-react  for Vue and React reference implementations.  That's it!",{"id":168,"path":169,"dir":159,"title":170,"description":171,"keywords":172,"body":176},"content:3.advanced-topics:10.listings-views.md","/advanced-topics/listings-views","Listings, Views","The Lupus Decoupled Views\nsubmodule provides support for Drupal's Views module. The Views module is Drupal's native way and very powerful way of creating listings of content. It provides a UI for configuring complex queries, searches and the rendering of results, including paging.",[173,174,175],"Usage","Video tutorial","Status","  Listings, Views  The   Lupus Decoupled Views \nsubmodule provides support for Drupal's Views module. The Views module is Drupal's native way and very powerful way of creating listings of content. It provides a UI for configuring complex queries, searches and the rendering of results, including paging.  As alternative to Views-based listings, the frontend may   create custom routes  and listings by querying the backend, see   JSON-API, GraphQL .  Usage  After enabling the sub-module, create a view, skip the wizard and follow the following steps:   Add   Custom elements display page  to a view (not a regular page!).  Select   Custom elements  style as view format.  Select   Content  as row style. Choose the view-mode you want to use for the listed elements.  Configure filters and other options as needed and set a path for the view.  The Custom elements API of the view is available at   /ce-api/\u003Cview-path> . Take note of the custom element name visible in the output, which will be   drupal-view-{ID} .  On the frontend clone the   drupal-view--default  component and create a component using the noted custom element name   drupal-view-{ID} . Test the view on the frontend at the configured path   \u003Cview-path>  and customize the component as desired.  Note that the chosen view-mode is automatically rendered with custom elements within the view. It's not required to force rendering it via custom elements.  Video tutorial  In the following tutorial an example configuration can be followed:     Note: The tutorial is a year old and uses   drupal-view  as custom element name. That changed meanwhile, use   drupal-view-{ID}  as custom element name or stay with the default   drupal-view--default .  Status   Support for Views is rather new and problems may arise with certain configurations. Please report any issues in the   Lupus Decoupled Drupal issue queue .  Atm there is no support for rendering exposed filter forms. So those need to be added manually in the frontend, when needed.  The Row style   Fields  is not supported yet (see\n  #3461874 ).  Items formatted as   Rendered entities  are supported. These are needed for   Search API Index Views .",{"id":178,"path":179,"dir":159,"title":180,"description":7,"keywords":181,"body":184},"content:3.advanced-topics:20.searches.md","/advanced-topics/searches","Searches",[182,183],"Searches with Views","Search API","  Searches  Searches with Views  Basic searches based upon simple SQL-queries can be built easily with the\nhelp of the Drupal Views module. Create a regular View and add one or more\nexposed filters, for example a fulltext filter. The frontend needs to build\na custom form for the search input and send the search input data as request\nquery parameters to the view.  Search API  The Drupal extension module   Search API  constitutes a powerful framework for building searches. While out-of-the-box it comes with a database backend, there are many modules providing support for powerful Search solutions available, for example:    Solr   Elasticsearch   OpenSearch   Typesense   Meilisearch   Algolia  The Search API module provides configuration for the content to be indexed, including configuration for the indexed data (and its processing) on a per-field basis. The content gets indexed whenever it is changed, either instantly or delayed via Drupal's cron service (as configured). For more details, please refer to the   Search API documentation .  Search API + Views  For building the actual Search page, again the Views module maybe be leveraged, by building a View with the Search API as query backend. Please refer to the   module documentation  for details on how to setup such a View. This might be a good option for simple searches.  Search index view could be configured to have a   Custom Elements Page \ndisplay and with that configuration a custom elements search endpoint is\navailable. (see   Lupus Decoupled Views )  Search API + Custom queries  A powerful alternative for building ambitious searches is to leverage the Search API module to index data to the search server and to have the frontend query the search server directly. That way, the frontend stays in control of the query and may make use of advanced search-server specific features in order to build a great, ambitious search experience!",{"id":186,"path":187,"dir":159,"title":188,"description":189,"keywords":190,"body":193},"content:3.advanced-topics:30.jsonapi-graphql.md","/advanced-topics/jsonapi-graphql","JSON-API & GraphQL","When data needs to be queried or updated from the frontend, Drupal offers plenty of options. Lupus Decoupled Drupal's provided API may be combined with any of these:",[191,192],"JSON-API","GraphQL","  JSON-API & GraphQL  When data needs to be queried or updated from the frontend, Drupal offers plenty of options. Lupus Decoupled Drupal's provided API may be combined with any of these:  JSON-API  Drupal core provides the JSON-API module, which is a RESTful API that works with all Drupal entities (and its access system) out-of-the-box. It comes with support for all CRUD operations, as well as custom queries. Following are the most relevant resources to get started:    Documentation   jsonapi-client npm package   Json:API Extras module  - Configure which entities are exposed   Simple OAuth  - Authenticate requests via API token  GraphQL  Alternatively, there are Drupal extension modules that add GraphQL support:    GraphQL module   GraphQL compose",{"id":195,"path":196,"dir":159,"title":197,"description":7,"keywords":198,"body":201},"content:3.advanced-topics:40.caching.md","/advanced-topics/caching","Caching",[199,200],"Page-level caching","Render caching","  Caching  Page-level caching  Lupus Decoupled Drupal takes advantages of Drupal's built-in caching system based around cache metadata. Given that the following modules provided by Drupal core work as usual:   Internal Page Cache - Caches page for anonymous users, with cache-tag based invalidation.  Dynamic Page Cache - Cache pages for authenticated users, with cache-tag based invalidation.  Since all the caching related HTTP headers get set correctly, also CDN or reverse-proxy (e.g. varnish) based caching works as usual. Just like with traditionally rendered Drupal pages, the pages rendered with custom elements have cache metadata associated, thus things like cache-tag based invalidation are supported.  Next, the following Drupal extension modules are great, optional additions and fully supported:    Purge module  - A general cache invalidation API, optionally with cache-tag based invalidation.  Varnish based cache and cache-tag invalidation via   Varnish Purger  Modules adding further cache backends, like   Redis  Various CDN modules, like   Cloudflare  Render caching  Since pages rendered into custom elements are skipping the Drupal internal, traditional render system, the Drupal-internal render-caching is bypassed. Instead of caching individual rendered pieces, whole pages can be cached well via dynamic page cache. Since the LupusCeRenderer module attaches the per-user rendered local tasks (the Drupal tabs) via a Kernel response event that is triggered after the Dynamic Page Cache, the pages can be cached efficiently across user-roles if the page-content is not user or role dependent. Additionally, the page response includes only the main content (no menus etc.), so it's often cacheable.",{"id":203,"path":204,"dir":159,"title":205,"description":7,"keywords":206,"body":209},"content:3.advanced-topics:50.error-pages.md","/advanced-topics/error-pages","Error pages",[207,208],"Drupal error pages","Custom error pages in Nuxt","  Error pages  Drupal error pages  Error pages provided by Drupal (e.g. 403, 404 page) are shown by default and can be configured in Drupal. Configuration is done in the Drupal backend under   Configuration > System > Basic site settings > Error pages . With server-rendering, the HTTP status code is correctly forwarded.  The Nuxt error page is only shown when the backend cannot be reached (error 504 Gateway timeout).  Custom error pages in Nuxt  In order to use regular Nuxt error pages for regular 403, 404 error pages, you can enable the   customErrorPages  option in   nuxt.config.js :     export   default   defineNuxtConfig  ({\n     drupalCe: {\n       customErrorPages:   true  ,\n       // options...\n     }\n   })\n  When custom error pages are active, the nuxt error handling is used for all error HTTP status codes returned by Drupal.  html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}",{"id":211,"path":212,"dir":159,"title":213,"description":7,"keywords":214,"body":220},"content:3.advanced-topics:60.drupal-forms.md","/advanced-topics/drupal-forms","Drupal forms",[215,216,217,218,219],"Overview","How does it work?","Rendering forms in the frontend","Supported Drupal forms","Webforms","  Drupal forms    Note:  At the moment Drupal forms are only supported with server-side   rendering mode .  Overview  The \"Lupus Decoupled Form\" sub-module makes it easy to support Drupal forms in a decoupled frontend. The form HTML is rendered by Drupal and wrapped in a   \u003Cdrupal-form>  custom element, such that the frontend can easily add some styling or custom JS-enhancements.  At the moment, progressive form submissions are supported, which work without JavaScript. JavaScript enhanced form submissions are currently not a priority, but can be achieved with some additional JavaScript code, see Issue   #3471135  for some code to get started.  How does it work?  Generally, Drupal renders the form as usual. The resulting HTML markup is wrapped into a   \u003Cdrupal-form-{FORM-ID}>  component, which simply shows the server-rendered HTML of the form. When the form is submitted, the frontend takes care of forwarding the POST request to the backend, where it's processed as usual. After form processing the request is rendered in a custom element response again: Either the page response contains a reloaded form or a redirect. Any messages for form validation fails or success are handled as usual via the   Drupal message system  and sent as part of the next page response. Thus, subsequently the frontend takes care of rendering the response appropriately in a new page or redirect response - just as it does for any other server-render page.  Frontend support   For the Nuxt frontend, The Nuxtjs Drupal-CE Connector module ships with a suitable default component:   drupal-form--default.vue  There is   server middleware  which takes care of handling the POST request and renders the response.  Rendering forms in the frontend  Generally, the   drupal-form--default  component may be used to add form styles and JavaScript as needed, either generally for all forms via the default component, or individually by customizing things in a per-form component   drupal-form--{FORM-ID} . Any Drupal CSS or JavaScript assets for the form elements won't be included in the decoupled frontend, thus the frontend needs to take care of providing suitable replacement style and scripts as necessary.  In order to change the HTML markup of forms, the form elements need to be themed in Drupal.  Theming form elements  Since the markup is generated by Drupal, the HTML of individual form elements can be altered only by adjusting the Drupal markup with the help of a Drupal theme:   For having a clean, semantic output of forms, the   lupus-stark theme  has been created - which\nadds suitable Drupal twig files to do away with unnecessary Drupal-isms. That way decent markup is\ngenerated and necessary style adaptions are made possible by targeting elements using the\nreasonable default classes.  Generally, the active Drupal theme can be customized by setting the theme as site-wide standard theme. If the form is on a Drupal admin page, the Admin Theme will be applied though.  The module adds support for a special '_theme' key in route definitions, which allows Drupal developers to switch themes to the given theme-name specifically for the form routes, as preferred.  Supported Drupal forms  Lupus Decoupled ships with further sub-modules that enable support for further Drupal-forms as desired:    Lupus Decoupled Contact Forms  - Adds support for the contact forms provided by the core contact module.   Lupus Decoupled User Forms  - Enables using Drupal user login and user password reset forms in the frontend. That way, user may login while getting a separate frontend cookie. Please refer to the   Authentication page  for details.  If you miss support for some Drupal form, please open an issue in the   Lupus Decoupled issue queue  to add it! Please refer to the page   Adding Drupal Forms  for documentation on how this is done.  Webforms  The Lupus Decoupled Webform module provides support for   Webform \nmodule (version 6.0 or later), a popular module for building forms using the UI.  Webforms integration utilizes the Lupus Decoupled Forms\nfunctionality (see   How it work?  section), thus\na webforms get a custom elements API endpoint.  Limitations  Drupal JavasScript are currently not provided by the webform API response,\nthus any webform elements relying on JavaScript are missing the Drupal JavaScript.  Confirmation types  Inline and page (default) confirmations are supported, but for page\nconfirmation type the user (or anonymous) needs to have access to \"view own\nwebform submissions\" set on webform settings configured at\n  admin/structure/webform/manage/{webform}/access  Submission example  A curl request example to submit a custom webform (with   test_ce_webform  id).\nNote that the submission webform id is   webform_submission_test_ce_webform_add_form .     curl   -k   -X   POST   --url   https://lupus-decoupled.ddev.site/ce-api/form/test_ce_webform   -F   'first_name=John'   -F   \"last_name=Doe\"   -F   \"checkbox=1\"   -F   \"op=Submit\"   -F   \"form_build_id=form-\u003Cform-build-id>\"   -F   \"form_id=webform_submission_test_ce_webform_add_form\"   -H   \"Accept: application/json\"\n  html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}",{"id":222,"path":223,"dir":159,"title":224,"description":225,"keywords":226,"body":229},"content:3.advanced-topics:65.site-templates.md","/advanced-topics/site-templates","Site Templates","Drupal CMS supports site templates: pre-configured starting points that combine Drupal recipes, a theme, design elements, and default content into a fully functional website ready to use from day one. See the Drupal blog post on site templates for the broader vision.",[227,228],"Lupus Decoupled Starter","Creating a New Site Template","  Drupal CMS Site Templates   Drupal CMS  supports   site templates : pre-configured starting points that combine Drupal recipes, a theme, design elements, and default content into a fully functional website ready to use from day one. See the   Drupal blog post on site templates  for the broader vision.  Lupus Decoupled Starter  The   Lupus Decoupled Starter  is the reference site template for Lupus Decoupled. It installs:    Lupus Decoupled Recipe : core decoupled modules and configuration   Lupus Decoupled Canvas : Canvas visual editor integration   Lupus CSR : client-side rendering theme with the   Nuxt Starter  (set as default)  It is the recommended way to get started with Lupus Decoupled on Drupal CMS and serves as a template for building new site templates.  Creating a New Site Template  To create a new Lupus Decoupled-based site template, use the Lupus Decoupled Starter as your starting point:    Fork or copy  the   lupus_decoupled_starter  repository. Alternatively, use   drush site:export  to export configuration from a running Drupal site and build a recipe from scratch — see   Drupal CMS Site Template Base  for the base structure to build upon.   Customize the recipe : add or remove modules, configuration, and default content to match your use case.   Provide a custom CSR theme : create a sub-theme of   lupus_csr  with your frontend build output, or configure a different frontend (see   Lupus CSR )  The starter's recipe structure mirrors Drupal CMS conventions, making it straightforward to adapt for industry-specific or purpose-built templates. To make your template available in the Drupal CMS marketplace, follow the   getting started guide .",{"id":231,"path":232,"dir":159,"title":233,"description":234,"keywords":235,"body":237},"content:3.advanced-topics:70.block-layout.md","/advanced-topics/block-layout","Block layout","As documented at Site layout & Menus by default the site header and footer are built by the frontend. That means, the Drupal Blocks Layout configuration is ignored for custom-elements rendered pages.",[236],"How does it work","  Block layout with Drupal  As documented at   Site layout & Menus  by default the site header and footer are built by the frontend. That means, the Drupal   Blocks Layout  configuration is ignored for custom-elements rendered pages.  However, with the optional \"Lupus Decoupled Blocks\" sub-module the configured blocks may be rendered and included with the page response. This may be useful when Drupal should generate the content for a certain region for every page, e.g. a sitebar.  How does it work  When the module \"Lupus Decoupled Blocks\" is enabled, all configured blocks are rendered with custom elements for every page. The result is grouped by region and added to the custom-elements page API response under a new top-level   blocks  key. In turn, the frontend just needs to render and place the custom-element content of each region on the page.",{"id":239,"path":240,"dir":159,"title":241,"description":242,"keywords":243,"body":245},"content:3.advanced-topics:80.debugging.md","/advanced-topics/debugging","Debugging API requests","For debugging API requests and responses, Lupus Decoupled Drupal offers\nintegration with REST Log\nmodule.",[173,244],"Set up","  Debugging API requests  For debugging API requests and responses, Lupus Decoupled Drupal offers\nintegration with   REST Log \nmodule.  In decoupled scenarios, visitors are making requests to the front-end application,\nwhich is itself retrieving data from the back-end. It is helpful to see the\nform of requests that reached the decoupled back-end and the responses that\nthe back-end provided.  Logged data consists of:   Request method  Request header  Request URI  Request cookie  Request payload  Response status  Response header  Response body  Response time  Usage  Make some requests either to API endpint (  /admin/content  view provides   View\nAPI Endpoint operation  for nodes that opens their API endpoint directly) or front-end\nrequests and investigate them at   /admin/reports/rest_log .  Set up    composer require --dev drupal/rest_log   drush en lupus_decoupled_api_log  Configuration  REST Log module's default configuration is sufficient but it can be changed at\n  /admin/config/development/logging/rest_log .  Debugging with curl  Sometimes it is useful to trigger   Xdebug  from the command\nline. This can be achieved with   curl . Authorization can be\nprovided via session cookie with values copied from the authenticated browser\nsession.  Example of such curl request:   curl -k -i -H 'Cookie: SSESS\u003Csession-name>=\u003Csession-cookie-value>;XDEBUG_SESSION=XDEBUG_ECLIPSE;' https://\u003Cdomain>/\u003CAPI-endpoint>\n",{"id":247,"path":248,"dir":7,"title":249,"description":7,"keywords":250,"body":251},"content:3.examples.md","/examples","Home",[],"    Drupal Dev Days 2023 - Session Video Recordings  Demos, showcases.",{"id":253,"path":254,"dir":7,"title":255,"description":7,"keywords":256,"body":263},"content:4.community.md","/community","Community",[257,258,259,260,261,262],"Chat","Video tutorials","Slides","Session recordings","Interviews","Blog posts","  Lupus Decoupled Community  Chat  Get in touch via the drupal Slack channel!   Join the   Drupal slack  Join channel   #lupus-decoupled  Video tutorials  There are a couple of   \"ddd23\" video tutorials  available, which have been recorded at the Drupal Dev Days Vienna 2023.  Slides    DrupalCon Vienna - 2025-10: JavaScript frontend development with Drupal Canvas: Beyond decoupling   Drupal Developer Days Leuven - 2025-04: Nuxt for Drupal Developers - Modern frontend without the JavaScript Jungle   Drupal Developer Days Burgas - 2024-06:  Custom Elements UI: quicker changes to\nyour decoupled Drupal site   DrupalDevDays 2023 Vienna - Lupus Decoupled Drupal  - Introduction by Wolfgang Ziegler // fago   Lupus Decoupled Drupal - Overview & Status   Drupalcon North America 2021 - Getting Started with the Lupus Nuxt.js Drupal Stack   Drupal DACH Meetup - 2021-04:  Decoupling Drupal with the Lupus Nuxt.js Drupal Stack  Session recordings   Drupal Developer Days Leuven 2025 - Nuxt for Drupal Developers: Modern Frontend Without the JavaScript Jungle   [Video]  DrupalDevDays 2023 Vienna - Lupus Decoupled Drupal   [Video]  Drupalcon NA 2021 - Getting Started with the Lupus Nuxtjs. Drupal Stack  [Video]  Drupalcon Europe 2020 - Custom Elements - An alternate Render API for decoupled Drupal\n  [Video]  Interviews    A Look Under the Hood of Lupus Decoupled Drupal - The DropTimes  Blog posts    Lupus Decoupled Drupal brings Inertia.js-Style Development to Drupal \nExplains how Lupus Decoupled enables Inertia.js-style development patterns.   Low-code + Decoupled Drupal: The Power of Custom Elements 3.0 \nIntroduces the Custom Elements UI module.   Custom Elements: A solution for soft-decoupled Drupal \nClarifies the goals and talks and explains the overall idea.   Nuxt.js - The frontend framework for decoupled Drupal with Custom Elements \nDiscusses selecting a frontend framework.   Lupus Decoupled Drupal: Bridging Drupal’s Backend Strength with Frontend Freedom \nGives an overview of Lupus Decoupled Drupal latest updates.   Why we don't use GraphQL \nExplains GraphQL limitations and alternative solutions.",{"id":265,"path":266,"dir":267,"title":268,"description":269,"keywords":270,"body":274},"content:4.drupal:10.key-modules.md","/drupal/key-modules","drupal","Key modules","Lupus Decoupled Drupal builds upon the following two key modules:",[271,272,273],"Lupus Decoupled Integration modules","Themes","Further Useful Drupal modules","  Key modules   Lupus Decoupled Drupal  builds upon the following two key modules:    Custom Elements   Lupus Custom Elements Renderer  The custom elements module forms the base: It provides the API to render entities into custom elements. Based upon that the Lupus CE renderer module integrates with the Drupal routing system and renders requests of format   custom_elements  using the custom elements module. On top of that, the    Lupus Decoupled Drupal  provides the \"Lupus Decoupled Custom Elements API sub-module, which makes this API available in a more opinionated way: It adds a handy   /ce-api  path-prefix and optionally handles redirection to the frontend.  Lupus Decoupled Integration modules   Lupus Decoupled Drupal  ships with more sub-modules that integrate modules like Views, or Forms with the stack.  Themes   Lupus CSR  is a Drupal base theme that enables serving a pre-built frontend application (e.g. a Nuxt build) directly from Drupal without a separate frontend server. It is the recommended approach for Drupal CMS site templates, demos, ready-made setups, and simple projects that do not require server-side rendering.  Further Useful Drupal modules  Besides the main modules, the following Drupal modules are useful:    Rest menu items  provides a way to easily\nfetch Drupal menus. The Nuxt Drupal module comes with built-in support for it.   Trusted redirect  allows the frontend\nto link to Drupal while setting a   destination=\u003Cfrontend_URL>  redirect target.   Services env parameter  to\nset cookie domain or CORS configuration via environment variables. This is what the   project template  does.",{"id":276,"path":277,"dir":267,"title":278,"description":7,"keywords":279,"body":284},"content:4.drupal:20.custom-elements.md","/drupal/custom-elements","Custom elements",[280,281,282,283],"Creating custom elements","Rendering into custom elements","Serializing to markup or JSON","Traditional render arrays","  Custom elements  Creating custom elements  The   CustomElement  class helps modelling a tree of custom elements. The class provides an API for creating and nesting custom elements as shown the following example:     \u003C?  php\n      use   \\Drupal\\custom_elements\\CustomElement  ;\n   \n      class   NewsController   extends   ControllerBase   {\n       public   function   buildNewsListing  () {\n   \n         $articles[]   =   CustomElement  ::  create  (  'article-teaser'  )\n           ->  setAttribute  (  'href'  ,   'https://example.com/news/1'  )\n           ->  setAttribute  (  'excerpt'  ,   'The excerpt of the news entry.'  );\n   \n         $articles[]   =   CustomElement  ::  create  (  'article-teaser'  )\n           ->  setAttribute  (  'href'  ,   'https://example.com/news/2'  )\n           ->  setAttribute  (  'excerpt'  ,   'The excerpt of another news entry.'  );\n   \n         return   CustomElement  ::  create  (  'teaser-listing'  )\n           ->  setSlotFromNestedElements  (  'default'  , $articles);\n       }\n     }\n  This creates:     \u003C  teaser-listing   title  =  \"Latest news\"   icon  =  \"news\"  >\n       \u003C  article-teaser\n           href  =  \"https://example.com/news/1\"\n           excerpt  =  \"The excerpt of the news entry.\"\n       >\n       \u003C/  article-teaser  >\n       \u003C  article-teaser\n           href  =  \"https://example.com/news/2\"\n           excerpt  =  \"The excerpt of another news entry.\"\n       >\n       \u003C/  article-teaser  >\n   \u003C/  teaser-listing  >\n  Slots  Slots are used for passing nested, arbitrary content. Slots are named and can have one or multiple child elements. The child elements keep their ordering, unless a custom weight is passed. The   default  slot is a special slot name, which is used for nested markup without a given slot-name, e.g.   \u003Cthe-element>some-nested-content\u003C/the-element> , which is the same as   \u003Cthe-element>\u003Cslot name=\"default\">some-nested-content\u003C/slot>\u003C/the-element> .  Attributes  Besides slot, an element may contain any number of attributes, which are key value pairs. Attribute values can be scalars and arrays, which - when rendered into markup format - become a JSON-encoded string.  Cache Metadata  Custom elements integrate with Drupal's   cache API , by allowing to define their caching dependencies via cache tags and their cache context. They implement the   CacheableDependencyInterface , so their cache dependencies can be easily added as usual, for example entities:     $custom_element  ->  addCacheableDependency  ($entity);\n  When a tree of elements is rendered, cache metadata of individual elements is aggregated and bubbled up to the page, just as with Drupal's traditional render system.  API documentation  For detailed API documentation please refer to the in-code API documentation of the   \\Drupal\\custom_elements\\CustomElement  class.  Rendering into custom elements  For rendering entities, and more generally any kind of data, into custom elements, the module provides the custom element generator service:         \u003C?  php\n       class   SomeClass   {\n         use   CustomElementGeneratorTrait  ;\n         public   function   someMethod  () {\n           $custom_element   =   $this  ->  getCustomElementGenerator  ()\n             ->  generate  ($entity, $view_mode);\n         }\n       }\n  This will render into custom elements as configured for the entity. Refer to   Customized API output  for an overview.  For other kind of data, for some field items, the data may be processed via \"automatic processing\" which makes use of   custom element processors :         \u003C?  php\n       class   SomeClass   {\n         use   CustomElementGeneratorTrait  ;\n         public   function   someMethod  () {\n           $element   =   CustomElement  ::  create  (  'some-element'  );\n           $this  ->  getCustomElementGenerator  ()\n             ->  process  ($items, $element, $view_mode);\n         }\n       }\n  Serializing to markup or JSON  A tree of custom elements can be output in   markup  or   JSON  format:  Serializing to JSON  For serializing a tree of custom elements into JSON make use of the provided normalizer:         \u003C?  php\n         $custom_element_normalizer   =   \\Drupal  ::  service  (  'custom_elements.normalizer'  );\n         $bubbleable_metadata   =   BubbleableMetadata  ::  createFromObject  ($custom_element);\n         $json   =   $custom_element_normalizer  ->  normalize  ($custom_element,   NULL  , [  'cache_metadata'   =>   $bubbleable_metadata]);\n  Serializing to markup  For generating markup for a tree of custom elements, simply render it via the Drupal's traditional render API:       \u003C?  php\n       $render   =   $custom_element  ->  toRenderArray  ();\n       $renderer   =   \\Drupal  ::  service  (  'renderer'  );\n       $markup   =   $renderer  ->  renderRoot  ($customElement);\n     ?>\n  Custom Element markup styles  Custom elements use \"slots\" for handling content distribution, i.e. for passing\nnested content to an element. However, the concrete syntax used for handling\nslots may differ by various frameworks. Thus, the module supports rendering to\ndifferent markup styles while it defaults to the Web component style syntax. In addition,\nthe module supports the   Vue2 and Vue 3  syntax which can be enabled via config:     drush   config:set   custom_elements.settings    markup_style   vue-3\n  Traditional render arrays  Custom elements may be rendered using Drupal's traditional render API:       \u003C?  php\n       $render[]   =   $custom_element  ->  toRenderArray  ();\n     ?>\n  On the other hand, it's possible to wrap a traditional render array into a custom element:       \u003C?  php\n       $custom_element   =   CustomElement  ::  createFromRenderArray  ($render_array);\n     ?>\n  The resulting element can be further customized, but by default it simply renders the   $render_array  and wraps it into a   \u003Cdrupal-markup>  element, that the frontend may simply output.  html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}",{"id":286,"path":287,"dir":267,"title":288,"description":289,"keywords":290,"body":292},"content:4.drupal:30.routes.md","/drupal/routes","Routes","The Lupus CE Renderer module takes care of rendering routes of the format custom_elements via Drupal's regular routing system. That means a route can be defined as usual in Drupal, additionally define the _format to be custom_elements:",[291],"Multiple routes at one path","  Routes  The Lupus CE Renderer module takes care of rendering routes of the format   custom_elements  via Drupal's regular routing system. That means a route can be defined as usual in Drupal, additionally define the   _format  to be   custom_elements :       MODULE  .  listing  :\n         path  :   '/news'\n         defaults  :\n           _title  :   'News Listing'\n           _controller  :   '\\Drupal\\MODULE\\Controller\\NewsController::buildNewsListing'\n         requirements  :\n           _format  :   'custom_elements'\n           _permission  :   'access content'\n  Next, the controller may simple return a custom element object:       \u003C?  php\n        class   NewsController   extends   ControllerBase   {\n         public   function   buildNewsListing  () {\n   \n           $articles[]   =   CustomElement  ::  create  (  'article-teaser'  )\n             ->  setAttribute  (  'href'  ,   'https://example.com/news/1'  )\n             ->  setAttribute  (  'excerpt'  ,   'The excerpt of the news entry.'  );\n   \n           $articles[]   =   CustomElement  ::  create  (  'article-teaser'  )\n             ->  setAttribute  (  'href'  ,   'https://example.com/news/2'  )\n             ->  setAttribute  (  'excerpt'  ,   'The excerpt of another news entry.'  );\n   \n           return   CustomElement  ::  create  (  'teaser-listing'  )\n             ->  setSlotFromNestedElements  (  'default'  , $articles);\n         }\n        }\n  The Lupus CE renderer module is taking care of rendering the element into either markup or JSON serialization:      {\n   \n       \"title\"  :   \"News Listing\"  ,\n       \"content_format\"  :   \"json\"  ,\n       \"content\"  : {\n             \"element\"  :   \"teaser-listing\"  ,\n             \"props\"  : {\n                   \"title\"  :   \"Latest news\"  ,\n                   \"icon\"  :   \"news\"\n             },\n             \"slots\"  : {\n                   \"default\"  : [\n                         {\n                               \"element\"  :   \"article-teaser\"  ,\n                               \"props\"  : {\n                                     \"href\"  :   \"https://example.com/news/1\"  ,\n                                     \"excerpt\"  :   \"The excerpt of the news entry.\"\n                               }\n                         },\n                         {\n                               \"element\"  :   \"article-teaser\"  ,\n                               \"props\"  : {\n                                     \"href\"  :   \"https://example.com/news/2\"  ,\n                                     \"excerpt\"  :   \"The excerpt of another news entry.\"\n                               }\n                         }\n                   ]\n             }\n       }\n   }\n     {\n       \"title\"  :   \"News Listing\"  ,\n       \"content_format\"  :   \"markup\"  ,\n       \"content\"  :   \"\n         \u003Cteaser-listing title=  \\\"  Latest news  \\\"   icon=  \\\"  news  \\\"  >\n           \u003Carticle-teaser to=  \\\"  https://example.com/news/1  \\\"   excerpt=  \\\"  The excerpt of the news entry.  \\\"   slot=  \\\"  default  \\\"  >\u003C/article-teaser>\n           \u003Carticle-teaser to=  \\\"  https://example.com/news/2  \\\"   excerpt=  \\\"  The excerpt of another news entry.  \\\"   slot=  \\\"  default  \\\"  >\u003C/article-teaser>\n         \u003C/teaser-listing>\"\n   }\n  Multiple routes at one path  Note that the routing system supports routes at the same path with varying formats, thus a   html  and a   custom_elements  formatted route can co-exist at the same path. This may be used to clone routes and to customize them as needed.     \n   /**\n    * Creates CE variants for user forms.\n    */\n   class   RouteSubscriber   extends   RouteSubscriberBase   {\n   \n     /**\n      * {  @inheritdoc  }\n      */\n     protected   function   alterRoutes  (  RouteCollection   $collection) {\n       // Provide CE variants for user forms.\n       $form_route_ids   =   [  'user.login'  ,   'user.pass'  ,   'user.register'  ];\n       foreach   ($form_route_ids   as   $form_route_id) {\n         $route   =   $collection  ->  get  ($form_route_id);\n         $ce_route   =   clone   $route;\n         $ce_route  ->  setRequirement  (  '_format'  ,   'custom_elements'  );\n         // Then customize the new route as needed:\n         $form   =   $route  ->  hasDefault  (  '_entity_form'  )   ?   'entity_form'   :   'form'  ;\n         $ce_route  ->  setDefault  (  '_controller'  ,   \"lupus_decoupled_form.controller.  $form  :getContentResult\"  );\n         // Add it to the route collection.\n         $collection  ->  add  (  \"lupus_decoupled.{  $form_route_id  }\"  , $ce_route);\n       }\n     }\n   \n   }\n  html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}",{"id":294,"path":295,"dir":267,"title":296,"description":297,"keywords":298,"body":300},"content:4.drupal:40.providing-blocks.md","/drupal/providing-blocks","Providing blocks","In order to provide blocks that render into custom elements, for example for using as part of the Layout Builder, the block cannot directly return a custom element object, since its interface requires a render array. Instead, simply return the custom element as render array via its helper toRenderArray(). When done so, the custom element is going to be picked up correctly when the layout is rendered.",[299],"Example block","  Providing blocks  In order to provide blocks that render into custom elements, for example for using as part of the   Layout Builder , the block cannot directly return a custom element object, since its interface requires a render array. Instead, simply return the custom element as render array via its helper   toRenderArray() . When done so, the custom element is going to be picked up correctly when the layout is rendered.  Example block     \n   /**\n    * Provides an example news listing block.\n    *\n    * @Block(\n    *   id = \"lupus_decoupled_drupal_example_news_listing\",\n    *   admin_label = @Translation(\"Example news listing\"),\n    *   category = @Translation(\"Custom\")\n    * )\n    */\n   class   ExampleNewsListingBlock   extends   BlockBase   {\n   \n     /**\n      * {  @inheritdoc  }\n      */\n     public   function   build  () {\n       $articles[]   =   CustomElement  ::  create  (  'article-teaser'  )\n         ->  setAttribute  (  'href'  ,   'https://example.com/news/1'  )\n         ->  setAttribute  (  'excerpt'  ,   'The excerpt of the news entry.'  );\n       $articles[]   =   CustomElement  ::  create  (  'article-teaser'  )\n         ->  setAttribute  (  'href'  ,   'https://example.com/news/2'  )\n         ->  setAttribute  (  'excerpt'  ,   'The excerpt of another news entry.'  );\n   \n       $teaser_listing   =   CustomElement  ::  create  (  'teaser-listing'  )\n         ->  setAttribute  (  'title'  ,   'Latest news'  )\n         ->  setAttribute  (  'icon'  ,   'news'  )\n         ->  setSlotFromNestedElements  (  'default'  , $articles);\n   \n       // Return the custom element as render array to fulfill the interface.\n       return   $teaser_listing  ->  toRenderArray  ();\n     }\n   \n   }\n  html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}",{"id":302,"path":303,"dir":267,"title":304,"description":305,"keywords":306,"body":307},"content:4.drupal:50.custom-element-processors.md","/drupal/custom-element-processors","Custom Element Processors","The custom elements module comes with Custom element processors that try to implement\na reasonable default for content entities and fields. These defaults can be\nfurther customized with custom modules as needed.",[],"  Custom Element Processors  The custom elements module comes with Custom element processors that try to implement\na reasonable default for content entities and fields. These defaults can be\nfurther customized with custom modules as needed.  The default entity processor renders the data of all visible fields either as\nattribute to the custom element tag, or as nested markup via a slot. The module\nmaps simple fields and their properties to attributes and falls back to\nrendering more complex fields to regular markup, which gets added as slot to\nthe parent custom element.  This method was the default in version 2.x and since 3.x, it's used when \"Use automatic processing\" is enabled in the Custom Elements display. Besides that, when \"Auto\" is selected for individual fields the field is formatted using processors.  Processors are provided via services, for example see   TextFieldItemProcessor  as registered at the   services.yml file .",{"id":309,"path":310,"dir":267,"title":311,"description":312,"keywords":313,"body":314},"content:4.drupal:60.add-drupal-forms.md","/drupal/add-drupal-forms","Adding Drupal forms","Lupus Decoupled Drupal supports submitting Drupal forms via the decoupled frontend, as documented under Advanced Topics - Drupal Forms.\nIn order to enable submitting another Drupal form on the frontend, a custom-elements enabled form processing route must be added. This is\ndone easily by:",[],"  Supporting more Drupal forms  Lupus Decoupled Drupal supports submitting Drupal forms via the decoupled frontend, as documented under   Advanced Topics - Drupal Forms .\nIn order to enable submitting another Drupal form on the frontend, a custom-elements enabled form processing route must be added. This is\ndone easily by:   Ensuring there is a custom-elements enabled route, e.g. by cloning the original one and\nadding   custom_elements  as   _format .  Pointing the custom-elements enabled route to a form controller that renders the results as\ncustom elements. For standard forms, the following controllers may be specified:   For general forms:   lupus_decoupled_form.controller.form:getContentResult  For entity forms:    lupus_decoupled_form.controller.entity_form:getContentResult  Else, a custom controller can be easily be provided with the help of the   CustomElementsFormControllerTrait ,\nsee the   lupus_decoupled_contact  submodule for an example.  That's it!  Generally, The   Lupus Decoupled Contact  module serves as\na simple example that demonstrates how support for contact forms is enabled.",{"id":316,"path":317,"dir":267,"title":318,"description":7,"keywords":319,"body":321},"content:4.drupal:70.themes.md","/drupal/themes","Providing themes",[215,320],"Lupus Client-Side Rendering (Lupus CSR)","  Providing Themes with JavaScript Rendering  Overview  Lupus CSR (Client-Side Rendering) themes allow you to bundle a pre-built frontend application directly as a Drupal theme, so no separate frontend server is needed. Drupal serves the frontend's   index.html  for all frontend routes; the frontend loads in the browser and fetches content from the CE API at   /ce-api/...  on the same origin.  This approach is ideal for:   Drupal CMS site templates where no separate frontend infrastructure is desired  Getting started quickly without setting up a Node.js server  Simple projects where SEO is not a primary concern  Note that client-side rendering means content is rendered in the browser via JavaScript. Search engines may not fully index CSR content. For production sites where SEO matters, use   server-side rendering  instead.  Lupus Client-Side Rendering (Lupus CSR)   Lupus CSR  is the Drupal base theme that enables this pattern. It intercepts Drupal's normal HTML output and delivers the frontend's   index.html  instead. Because the frontend communicates with   /ce-api/...  on the same origin, CORS configuration is not needed and Drupal authentication works out of the box.  Install it via Composer:     composer   require   drupal/lupus_csr\n  Using Lupus CSR Directly  The simplest approach: enable Lupus CSR as your active theme and configure it through the theme settings form at   /admin/appearance/settings/lupus_csr . Set a separate admin theme (e.g. Claro) to keep the Drupal backend accessible.  The frontend redirect in Lupus Decoupled settings is not needed with theme-based rendering and can stay disabled.  Creating a Sub-Theme  For distributable or project-specific setups, create a sub-theme of   lupus_csr  and include your frontend build output in a   dist/  directory. The   lupus_csr  module includes an example Nuxt starter in its   examples/  directory. Refer to the   Lupus CSR sub-theme guide  for configuration details.  Canvas Integration  If the theme's preview provider supports it, components are automatically registered with   Canvas ExtJS  when the theme is installed. The component index is read from the theme's bundled build output.  html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}",{"id":323,"path":324,"dir":7,"title":325,"description":7,"keywords":326,"body":328},"content:5.ddd23.md","/ddd23","Drupal Dev Days 2023 Videos",[327],"Drupal Dev Days 2023 Video Recordings","  Drupal Dev Days 2023 Video Recordings    Project Setup   Adding a field   Preparing content   Configure Views   Views Frontend   Layout builder",{"id":330,"path":331,"dir":332,"title":333,"description":334,"keywords":335,"body":341},"content:5.nuxt:10.introduction.md","/nuxt/introduction","nuxt","Introduction","Nuxt is an open source framework under MIT license that makes web development simple and powerful.",[336,337,338,339,340],"Flexible hosting","Outstanding performance","SEO & Web Vitals","Rich ecosystem","Great DX","  Intro to Nuxt   Nuxt  is an open source framework under MIT license that makes web development simple and powerful.   Like Drupal, it's extensible using   modules .  Thanks to the   Drupal Custom Elements Connector module  Nuxt simply works with Lupus Decoupled Drupal.  Thanks to   Vue.js  and its template-like   Single File Components  it's easy to get started and developers can focus on writing standard HTML, CSS and JavaScript in their Vue components.  Flexible hosting  With Nuxt you can decide what rendering strategy you want to use, if you like even at the route level: SSR, SSG, CSR. Build any kind of website or web application with optimized performance in mind.  Outstanding performance  Nuxt comes with many optimizations, e.g. code-splitting, tree-shaking, link prefetching, payload extraction, just to name a few. It's built for serverless usage, has optimized cold-starts and is small enough to be deployed to the edge.  SEO & Web Vitals  By leveraging server-side rendering, code-splitting and optimized images, Nuxt websites are indexable by search engines while providing an optimized user experience to end-users.  Rich ecosystem  There are many useful   modules  available that extend Nuxt, like   nuxt-i18n  and   nuxt-seo .  Great DX  As usual, Nuxt comes with a built-in dev-mode that instantly hot-reloads during development (simply run   npm run dev ). Moreover, the   Nuxt devtools  provide great in-browser dev-tooling and introspection possibilities.",{"id":343,"path":344,"dir":332,"title":345,"description":346,"keywords":347,"body":349},"content:5.nuxt:20.setup.md","/nuxt/setup","Setup","The Drupal Custom Elements Connector makes it easy to connect Nuxt with Lupus Decoupled Drupal and provide scaffold components to get started.",[348],"Steps","  Setup  The   Drupal Custom Elements Connector  makes it easy to connect Nuxt with Lupus Decoupled Drupal and provide scaffold components to get started.  Steps   Add the nuxt module   nuxtjs-drupal-ce  to your Nuxt project:     npx   nuxi@latest   module   add   drupal-ce\n   Configure the module in your nuxt config file   nuxt.config.js     export   default   defineNuxtConfig  ({\n     modules: [\n       'nuxtjs-drupal-ce'  ,\n     ],\n     drupalCe: {\n       drupalBaseUrl:   'https://your-drupal.example.com'  ,\n       // more options...\n     }\n   })\n  The module defaults work well with   Lupus Decoupled Drupal , so setting the   drupalBaseUrl  is usually enough. Howsoever, a complete list of options can be found in the module   README .   The module provides a set of scaffold files to get started quickly.  To generate the scaffold pages and components, run:     rm   -f   app.vue   &&   npx   nuxt-drupal-ce-init\n  The full list of scaffolded files is available in the   nuxtjs-drupal-ce repository .  html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}",{"id":351,"path":352,"dir":332,"title":353,"description":354,"keywords":355,"body":359},"content:5.nuxt:30.render-custom-elements.md","/nuxt/render-custom-elements","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.",[356,357,358],"Basics","Mapping attributes to props","Rendering slots","  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:     \u003C  template  >\n     \u003C  div   class  =  \"node\"  >\n       \u003C  h2   v-if  =  \"title\"  >Node: {{ title }}\u003C/  h2  >\n     \u003C/  div  >\n   \u003C/  template  >\n   \n   \u003C  script   setup   lang  =  \"ts\"  >\n   defineProps\u003C{\n     title  ?:   string;\n   }>()\n   \u003C/  script  >\n  Rendering slots  Rendering slots in Vue components works seamlessly with both JSON and markup serialization. Simply use native Vue slots in your template:     \u003C  template  >\n     \u003C  slot   name  =  \"body\"   /  >\n   \u003C/  template  >\n   \n   \u003C  script   setup   lang  =  \"ts\"  >\n   // Optional: Define slots for better TypeScript support\n   defineSlots  \u003C{\n     body  ()  :   any  ;\n   }>()\n   \u003C/  script  >\n  This works with both JSON and markup serialization. The Nuxt Drupal CE connector automatically handles the slot content in both cases.  JSON serialization (default)  With JSON-formatted custom elements, slot content is automatically mapped to Vue slots. You can use named slots or the default slot:     \u003C  template  >\n     \u003C  div   class  =  \"card\"  >\n       \u003C  slot   name  =  \"header\"   /  >\n       \u003C  slot   /  >\n       \u003C  slot   name  =  \"footer\"   /  >\n     \u003C/  div  >\n   \u003C/  template  >\n   \n   \u003C  script   setup   lang  =  \"ts\"  >\n   // Optional: Define slots for TypeScript\n   defineSlots  \u003C{\n     header  ()  :   any  ;\n     default  ()  :   any  ;\n     footer  ()  :   any  ;\n   }>()\n   \u003C/  script  >\n  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\n   export   default   {\n     vue: {\n       runtimeCompiler:   true\n     }\n   }\n  Then, slots will be directly passed as Vue slots.       \u003C  slot   name  =  \"body\"  >Fallback content.\u003C/  slot  >\n  Full example  Here is an example of a component that leverages props and slots and works with both markup and JSON serialization:     \u003C  template  >\n     \u003C  div   class  =  \"node\"  >\n       \u003C  h2   v-if  =  \"  title  \"  >Node: {{ title }}\u003C/  h2  >\n       \u003C  slot   name  =  \"body\"   /  >\n     \u003C/  div  >\n   \u003C/  template  >\n   \n   \u003C  script   setup   lang  =  \"ts\"  >\n   // Optional: Define slots for TypeScript\n   defineSlots  \u003C{\n     body  ()  :   any  ;\n   }>()\n   defineProps  \u003C{\n     title  ?:   string  ;\n   }>()\n   \u003C/  script  >\n  html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}",{"id":361,"path":362,"dir":332,"title":363,"description":364,"keywords":365,"body":367},"content:5.nuxt:32.default-components.md","/nuxt/default-components","Default components","Note: This feature is atm only available when using the (default) JSON-based rendered of custom elements.",[215,366],"Use-case","  Default components   Note : This feature is atm only available when using the (default) JSON-based rendered of custom elements.  Overview  When using JSON-based rendering of custom elements, the module offers fallback component support. If a custom element lacks a corresponding Vue component, the module attempts to find a suitable default component.  Use-case  This feature makes it possible to define a general custom element, e.g. for drupal forms   drupal-form--default.vue , which is used to render every custom element   drupal-form-*  when no specific custom element is available. That way, specific elements provided by Drupal, e.g.   drupal-form-user-login-form.vue , have the default applied, while it's easily possible to copy and customize the default component.  The same way it becomes handy to have general default components for content entities, like   node--default.vue , paired with element names like   node-article-page . That way it's easy to implement a general default component that suits multiple cases, while specific elements can easily be customized.  How it works:   The module removes the last   - -separated prefix from the element name.  It then appends a   --default  suffix.  If this modified component exists, it's used for rendering.  If the component is not exiting, the process is repeated.  Example lookup process  When a specific component isn't found, the module searches for a default component by progressively removing segments from the custom element name. For example when rendering the custom element   node-custom-view  it looks for components in the following order:   x node-custom-view.vue\nx node-custom-view--default.vue\nx node-custom--default.vue\n✓ node--default.vue\n",{"id":369,"path":370,"dir":332,"title":371,"description":372,"keywords":373,"body":376},"content:5.nuxt:35.composables.md","/nuxt/composables","Composables","The composable provided by the module provides helpers to fetch page and menu data, handle errors, and render custom components.",[374,375],"useDrupalCe","Example usage","  Composables  The composable provided by the module provides helpers to fetch page and menu data, handle errors, and render custom components.  useDrupalCe  This composable exports a collection of utilities to handle Drupal content and functionality.  Page Handling    fetchPage(path: string, query?: Object, errorHandler?: Function, skipProxy?: boolean)  - Fetches a page by path   getPage()  - Returns the current page state   usePageHead(page: Ref\u003Cany>, include?: Array\u003C'title' | 'meta' | 'link' | 'jsonld'>)  - Sets page head metadata from Drupal data   getPageLayout(page?: Ref\u003Cany>)  - Gets current page layout name (defaults to 'default')  Menu Handling    fetchMenu(name: string, options?: Object, errorHandler?: Function, skipProxy?: boolean)  - Fetches a menu by name  Component Rendering    renderCustomElements(elements: string | object | Array)  - Renders one or multiple custom elements from JSON data   resolveCustomElement(element: string)  - Resolves a custom element name to a Vue component  Messages    getMessages()  - Returns Drupal messages of the current page  API Utilities    $ceApi(options?: Object, skipProxy?: boolean)  - Creates a configured fetch instance   useCeApi(path: string, options?: Object, passThroughHeaders?: boolean, skipProxy?: boolean)  - Fetches data from Drupal CE API endpoint   getCeApiEndpoint(localize?: boolean)  - Gets API endpoint with optional localization   getDrupalBaseUrl()  - Gets configured Drupal base URL   getMenuBaseUrl()  - Gets configured menu base URL  Example usage  The following example makes use of the   fetchPage  method to get the current page:     \u003C  script   setup  >\n     const { fetchPage } = useDrupalCe()\n     const page = await fetchPage(useRoute().path)\n   \u003C/  script  >\n  html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}",{"id":378,"path":379,"dir":332,"title":380,"description":381,"keywords":382,"body":386},"content:5.nuxt:40.custom-routes.md","/nuxt/custom-routes","Custom Routes","Custom frontend routes are routes that are not defined in Drupal. They are defined in the frontend and can be used create custom pages.",[383,384,385],"Routing overview","Defining frontend routes","Handling route misses","  Custom Routes  Custom frontend routes are routes that are not defined in Drupal. They are defined in the frontend and can be used create custom pages.  Routing overview  In your Nuxt application, the routing mechanism runs in the following order:    Nuxt Routing:  It attempts to align the navigated path with one of the predefined routes located in your   pages  directory.   Nuxt Route Fallback:  If no predefined routes match, the system defaults to the wildcard route   pages/[...slug].vue . This wildcard route forwards requests to Drupal, such that the regular Drupal routing can handle the request.  Defining frontend routes  In the frontend, the Drupal routing is managed by the wildcard   pages/[...slug].vue  file within the pages directory.  In order to create a custom route in the frontend:   Go to the   pages  directory.  Create a new file with the desired route name. For instance, if you want a route named   search , create a file called   search.vue .  For more information on routing in Nuxt, see the   Nuxt routing documentation .  Handling route misses  In the event that no matching route is found by Drupal, by default, error pages provided by Drupal (e.g. 403, 404 page) are shown, while keeping the right status code. However, it's possible to take-over error handling in Nuxt as well. Please refer to the   error handling topic .",{"id":388,"path":389,"dir":332,"title":390,"description":391,"keywords":392,"body":397},"content:5.nuxt:50.page-layouts.md","/nuxt/page-layouts","Page Layouts","Nuxt layouts are placed in the ./layouts directory and are used to define a shared site layout\nfor a group of pages. When a page has a different layout, nuxt takes care of swapping the layout component(s).",[393,394,395,396],"Create a layout","Drupal controlled layouts","Setting the layout in the frontend","Nuxt layout documentation","  Page Layouts  Nuxt layouts are placed in the   ./layouts  directory and are used to define a shared   site layout \nfor a group of pages. When a page has a different layout, nuxt takes care of swapping the layout component(s).  For example, you can have a   default.vue  layout that is used for most pages, and a   blog.vue  layout that is used for\nall blog posts.  Create a layout  To create a layout, simply create a   .vue  file in the   ./layouts  directory.     \u003C  template  >\n     \u003C  div  >\n       \u003C  h1  >Blog layout\u003C/  h1  >\n       \u003C  slot   /  >\n     \u003C/  div  >\n   \u003C/  template  >\n  Drupal controlled layouts  The Drupal page API comes with a   page_layout  attribute within its response. By default, this is used to control which\nlayout is applied by Nuxt. This allows Drupal code to customize the layout used by Nuxt.  To set a custom layout from within Drupal, the   page_layout  attribute must be set accordingly, e.g. via\n  hook_lupus_ce_renderer_response_alter() .  Setting the layout in the frontend  The frontend may set a custom layout by proving a custom page component for some routes. For example, to change the\nlayout for all   /news/*  routes controlled by Drupal via the page API, create a component   news/[...slug].vue  in the\npages directory of Nuxt. Then make the page component follow the logic of the default page component, but override the\nlayout to be hard-coded:     \u003C  script   lang  =  \"ts\"  >\n     import   DefaultPage   from   '../[...slug].vue'\n   \n     export   default   {\n       extends: DefaultPage,\n       async   setup  () {\n         const   {   fetchPage  ,   renderCustomElements  ,   usePageHead  ,   getPageLayout   }   =   useDrupalCe  ()\n         const   page   =   await   fetchPage  (  useRoute  ().path, {\n           query:   useRoute  ().query,\n         },   undefined  ,   true  )\n   \n         const   layout   =   'custom'\n         usePageHead  (page)\n   \n         return   {\n           page,\n           layout,\n           renderCustomElements,\n         }\n       },\n     }\n   \u003C/  script  >\n  Nuxt layout documentation  For more information on routing in Nuxt.js, see the   Nuxt layouts documentation .  html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}",{"id":399,"path":400,"dir":332,"title":401,"description":402,"keywords":403,"body":407},"content:5.nuxt:55.component-previews.md","/nuxt/component-previews","Component Previews","Component previews allow Vue components to be rendered in isolation in external contexts, such as the Drupal Canvas editor. This enables editors to see live previews of components directly in the page builder.",[404,405,406,139],"Component Index","JSDoc Metadata","Drupal Canvas Types","  Component Previews  Component previews allow Vue components to be rendered in isolation in external contexts, such as the   Drupal Canvas  editor. This enables editors to see live previews of components directly in the page builder.   nuxt-component-preview  implements this for Nuxt/Vue. It enables previewing components in external contexts and auto-generates a component index for   Drupal Canvas  integration.  If you are using the   Nuxt Starter  or   nuxtjs-drupal-ce , the module is already pre-configured — no setup needed.  Component Index  The module auto-generates a component index at   /nuxt-component-preview/component-index.json , listing all global components with their metadata and prop schemas. This is what   Canvas External JS Components  (a Canvas extension for integrating external JavaScript components) reads to populate the Canvas editor.  Only   global  components are included. Components in   components/global/  are automatically global; others can be registered with   global: true  in   nuxt.config.ts .  Grouping Components by Folder  A recommended pattern is to keep Canvas components in a dedicated   components/Canvas/  folder and derive categories from subfolder names:     components  : [\n     { path:   '~/components/Canvas'  , global:   true  , pathPrefix:   false  , prefix:   ''   },\n     { path:   '~/components/global'  , global:   true   },\n     '~/components'  ,\n   ],\n   \n   componentPreview  : {\n     componentIndex  : {\n       // Derive Canvas component categories from folder names (Base/, Layout/, Card/, Hero/)\n       category  : {   directory  :   true  ,   fallback  :   'Misc'   },\n     },\n   },\n  For working examples, see the   Canvas components in the Lupus Decoupled Nuxt Starter .  JSDoc Metadata  Both components and their props are documented via TypeScript, with JSDoc annotations used to provide additional metadata that TypeScript alone cannot express. The pattern is consistent: a label (display name) and an optional description, plus additional tags.  Component Metadata  Define component-level metadata via a JSDoc comment at the top of   \u003Cscript setup> :     \u003C  script   setup   lang  =  \"ts\"  >\n   /**\n    * Hero Billboard\n    *   @description   A full-width hero section with background image and overlay.\n    *   @category   Hero\n    *   @status   stable\n    */\n   \u003C/  script  >\n     Tag  Description    First line  Label / display name (falls back to auto-generated from PascalCase)    @description  Component description shown in the editor    @category  Category override (alternative to directory-based)    @status   experimental ,   stable ,   deprecated , or   obsolete  All fields are optional. Config-level overrides take priority over JSDoc.  Prop Metadata  Props follow the same pattern — a label and description, plus additional tags for editor behavior:     \u003C  script   setup   lang  =  \"ts\"  >\n   withDefaults  (  defineProps  \u003C{\n     /**\n      * Button label text\n      *   @example   Submit\n      */\n     label  ?:   string\n     /**\n      * Button variant\n      *   @enumLabels   {\"large\": \"Extra Large (XL)\"}\n      */\n     variant  ?:   'primary'   |   'secondary'   |   'large'\n   }>(), {\n     label:   'Click me'  ,\n     variant:   'primary'\n   })\n   \u003C/  script  >\n  The prop label is auto-generated from the first JSDoc line or prop name. Use   @title  to override.     Tag  Description     @title  Explicit label override    @example  Adds example values (multiple allowed)    @enumLabels  Custom labels for enum values, e.g.   {\"large\": \"Extra Large (XL)\"}    @contentMediaType text/html  Enables rich text editing in Canvas for string props    @formattingContext block|inline  Controls formatting context (default:   block )    @schemaRef  Reference Canvas JSON schema definitions (e.g.   canvas/stream-wrapper-uri )    @format  JSON Schema format for semantic validation and UI widgets:   date ,   date-time ,   time ,   duration ,   email ,   hostname ,   ipv4 ,   ipv6 ,   uuid ,   uri ,   uri-reference , etc.    @pattern  JSON Schema regex pattern for string validation    @allowed-schemes  Allowed URI schemes for Canvas field type detection (e.g.   public  or   http, https )  Drupal Canvas Types  For   Drupal Canvas  integration, special TypeScript types are available that generate JSON schemas enabling Canvas UI features like media library selection. These types are auto-imported by Nuxt.     Type  Description     CanvasImage  Image with media library integration (src, alt, width, height)    CanvasVideo  Video with poster support  Example usage:     \u003C  script   setup   lang  =  \"ts\"  >\n   /**\n    * Hero Banner\n    */\n   defineProps  \u003C{\n     /**\n      * Background image\n      *   @example   src=https://example.com/hero.jpg alt=\"Hero\" width=1200 height=600\n      */\n     image  :   CanvasImage\n   }>()\n   \u003C/  script  >\n  The   @example  for Canvas types supports two formats:   Key-value:   src=https://... alt=\"text\" width=800 height=600  JS object:   { src: 'https://...', alt: 'text', width: 800 }  Schema References  For advanced use cases,   @schemaRef  allows referencing Canvas JSON schema definitions directly, useful for types like   stream-wrapper-uri  and   stream-wrapper-image-uri . Use the shorthand   prefix/name  notation:     /**\n    * @schemaRef canvas/stream-wrapper-uri\n    */\n   imageUri?: string\n  This expands to   json-schema-definitions://canvas.module/stream-wrapper-uri .  Manual Setup  If you are not using the Nuxt Starter or nuxtjs-drupal-ce, install and configure the module manually.  Install the module:     npm   install   nuxt-component-preview\n  Add it to   nuxt.config.ts  and add   \u003CComponentPreviewArea />  to   app.vue :     export   default   defineNuxtConfig  ({\n     modules: [  'nuxt-component-preview'  ],\n   })\n     \u003C  template  >\n     \u003C  ComponentPreviewArea   v-if  =  \"  useRuntimeConfig  ().public.componentPreview  \"   />\n     \u003C  NuxtPage   v-else   />\n   \u003C/  template  >\n  When embedding previews from a different domain (e.g. a Drupal backend), disable the app manifest in development to avoid relative URL failures:     $development  : {\n     experimental  : {\n       appManifest  :   false\n     }\n   }\n  For CORS configuration, see the   nuxt-component-preview CORS setup . When using nuxtjs-drupal-ce, CORS is configured automatically.  html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}",{"id":409,"path":410,"dir":332,"title":411,"description":412,"keywords":413,"body":417},"content:5.nuxt:60.rendering-modes.md","/nuxt/rendering-modes","Rendering modes","With Nuxt you can decide what rendering strategy you want to use, if you like even at the route level.",[414,415,416],"Server-side Rendering (SSR) - default","Static-site Generation (SSG)","Client-side Rendering (CSR)","  Rendering modes  With Nuxt you can decide what rendering strategy you want to use, if you like even at the route level.   Please refer\nto the Nuxt documentation about   Rendering modes  to learn more.  The following provides some additional overview about implication of each rendering mode when using it with Lupus Decoupled Drupal:  Server-side Rendering (SSR) - default  Server-side rendering is used as a default, which is best for SEO, and works the most seamlessly for editors thanks to the\nsupport of Drupal authentication. Nuxt supports server-rendering via regular (Node.js) servers or in a serverless way, e.g. at the   edge .  Static-site Generation (SSG)  Static-site generation results in a set of pre-generated files which a regular HTTP server or a CDN can serve, what can help to\nmake hosting much more simple.  Additionally, by publishing only static files, site security can be improved. However, there is also a drawback:\nEditors need to be aware of the pre-rendering step, the frontend is static and no drupal-forms are supported (atm). Nuxt supports a   preview-mode  which can be implemented and provided to editors though. Read more about it in the Nuxt   Prerendering Guide .  Client-side Rendering (CSR)  When SEO is not important and a small client-side rendering delay is acceptable to users, client-side rendering can\nbe a simple alternative to server-side rendering, that does not require any special infrastructure.  Just like with SSG, simply hosting static files is enough. At the moment, no drupal-forms are supported, but Drupal authentication works with the help of the Lupus Decoupled CORS sub-module.  For a zero-infrastructure alternative, see   Providing Themes :   Lupus CSR  allows bundling the frontend directly as a Drupal theme, with no separate frontend needed. The frontend is served from Drupal and fetches content from the CE API on the same origin.",{"id":419,"path":420,"dir":332,"title":421,"description":422,"keywords":423,"body":427},"content:5.nuxt:70.deployment.md","/nuxt/deployment","Deployment options","The deployment of Nuxt largely depends on the frontend rendering mode chosen. Please refer to the\nNuxt deployment guide for additional details.",[424,425,426],"Server-rendered","Static hosting","Supported presets","  Deployment options  The deployment of Nuxt largely depends on the frontend   rendering mode  chosen. Please refer to the\nNuxt   deployment guide  for additional details.  Server-rendered    Run a Node.js Server  - Useful for deploying Nuxt apps to any Node.js hosting.   Details   Edge-Side Rendering  - Run nuxt close to the user, e.g. at edge servers of a CDN.   Details  Nuxt uses Nitro as its server framework. Thus, also refer to the   Nitro deployment documentation  for additional details.\nFor deployments via Docker, an example Dockerfile can be found   here .  Static hosting    Static Site Generation  prerenders the site during build time.   Details   Client-side rendering  renders everything the browser.   Details  For serving static files a general web-server is generally good-enough, additionally there are   deployment presets  available that make it\neasy to trigger the pre-rendering process and serve the resulting build, e.g. with Github or Gitlab pages.  Supported presets  Nuxt comes with lots of supported presets. Refer to the   Nuxt deployment presets .",{"id":429,"path":430,"dir":332,"title":431,"description":7,"keywords":432,"body":435},"content:5.nuxt:90.resources.md","/nuxt/resources","Resources",[433,434],"Lupus Decoupled Nuxt resources","General Nuxt resources","  Resources  Lupus Decoupled Nuxt resources    Nuxt Drupal CE Connector   Naked demo project   Shad-CN Demo project  Legacy    Nuxt 2 demo project (legacy)  General Nuxt resources    Nuxt website   Nuxt docs   Nuxt modules",{"id":437,"path":438,"dir":439,"title":440,"description":441,"keywords":442,"body":445},"content:6.deployment:10.deployment-strategy.md","/deployment/deployment-strategy","deployment","Deployment Strategies","Lupus Decoupled Drupal supports two fundamentally different deployment approaches: running the frontend as a separate service, or bundling it directly as a Drupal theme.",[443,444],"Separate Frontend","Theme-Based Deployment (CSR)","  Deployment Strategies  Lupus Decoupled Drupal supports two fundamentally different deployment approaches: running the frontend as a separate service, or bundling it directly as a Drupal theme.  Separate Frontend  With a separate frontend, a standalone frontend server (e.g. a Node.js/Nuxt server) handles page rendering and communicates with Drupal via the CE API. This is the default approach for production sites where SSR or SSG is needed.  Within this approach, there are two hosting strategies:  Separated Deployment  The frontend and Drupal backend are deployed and hosted independently. This offers:   Faster frontend deployments without dependency on Drupal maintenance windows  Freedom to choose specialized frontend hosting solutions (e.g. serverless edge deployments)  Independent scaling and optimization of each component  However, this adds complexity in coordinating multiple environments. For Nuxt frontends, see the   Nuxt deployment docs .  Unified Deployment  Frontend and Drupal backend are hosted together in a single environment. This:   Requires a hosting environment capable of running both frontend (e.g. Node.js) and Drupal  Simplifies deployment coordination and environment management  Enables direct communication between services (e.g. cache or search servers)  A list of unified hosting possibilities can be found   here .  Frontend Rendering Modes  Both strategies support multiple rendering modes (SSR, SSG, CSR). By default, Lupus Decoupled uses a Nuxt frontend with server-side rendering. Refer to the   Nuxt rendering modes  or your frontend framework's documentation for details.  Theme-Based Deployment (CSR)  With   Lupus CSR , the pre-built frontend application is bundled directly as a Drupal theme. No separate frontend server is needed:   Any standard Drupal hosting works  The frontend application is deployed alongside Drupal as part of the theme  It fetches content from   /ce-api/...  on the same origin  This is the simplest deployment strategy and the default for   Drupal CMS site templates . The trade-off is client-side rendering, which is not ideal for SEO-critical sites.",{"id":447,"path":448,"dir":439,"title":449,"description":7,"keywords":450,"body":454},"content:6.deployment:20.unified-hosting.md","/deployment/unified-hosting","Unified Hosting",[451,452,453],"Amazee.io","Pantheon.io","upsun","  Unified hosting options   If you are using   theme-based deployment , any standard Drupal hosting works without Node.js support. The options below are for setups with a separate frontend server.  The following (in-complete) list of hosting providers offer specialized Drupal hosting while being able to host a decoupled\nfrontend.  Amazee.io  Amazee.io provides a managed open source hosting platform based on Kubernetes. It offers   Drupal hosting  and Node.js\nsupport. It provides the flexibility to add backend and frontend in one project, or as separate projects.  Pantheon.io  Pantheon.io offers   Drupal hosting  and optionally a decoupled   frontend site \nas well. Still, the frontend is deployed separately from the backend, so each system can be deployed on its own.  See the   Deploy on Pantheon  guide for step-by-step instructions.  upsun  upsun (by platform.sh) is a cloud application platform. It offers   Drupal support  as well as   Node.js support . Depending on the\nconfiguration, frontend and backend can be deployed as a single app, or as two separate apps.",{"id":456,"path":457,"dir":439,"title":458,"description":7,"keywords":459,"body":467},"content:6.deployment:30.pantheon.md","/deployment/pantheon","Deploy on Pantheon",[460,461,462,463,464,465,466],"Prerequisites","Step 1: Create the frontend site on Pantheon","Step 2: Prepare your frontend","Step 3: Push to Pantheon","Step 4: Wait for the build","Step 5: Verify","Node.js version","  Deploy on Pantheon   Pantheon's Next.js hosting is currently in   invite-only beta . You need beta access enabled on your Pantheon workspace before you can create Next.js sites.  Pantheon's   Next.js Beta  hosting supports deploying   Next.js  frontends with Lupus Decoupled Drupal. Since the platform uses a framework-agnostic Node.js build pipeline under the hood,   Nuxt  frontends also work.  Prerequisites   A Pantheon workspace with Next.js Beta access enabled  A Drupal site with   lupus_decoupled  installed and the custom elements API working  A GitHub account connected to your Pantheon workspace  Step 1: Create the frontend site on Pantheon   Go to Pantheon Dashboard →   Add Site  →   Next.js  Choose   \"Create new repository\"   Do   not  use \"Connect existing repository\" — it fails silently without any error message. Let Pantheon create the repo first, then push your code to it.   Wait for the initial template deployment to succeed  Note the GitHub repo that was created (e.g.   your-org/your-site-name )  Step 2: Prepare your frontend  Clone a Lupus Decoupled frontend starter:      git   clone   https://github.com/drunomics/lupus-decoupled-nuxt-starter.git   my-frontend\n     git   clone   https://github.com/drunomics/lupus-decoupled-nextjs-example.git   my-frontend\n  Configure it to point at your Pantheon Drupal backend. The recommended approach is to set the Drupal base URL as an environment variable on Pantheon via   Dashboard → Settings → Environment Variables  (only available after the first successful deployment):      NUXT_PUBLIC_DRUPAL_CE_DRUPAL_BASE_URL  =  https://dev-your-drupal-site.pantheonsite.io\n     NEXT_PUBLIC_DRUPAL_BASE_URL  =  https://dev-your-drupal-site.pantheonsite.io\n  Alternatively, you can set the base URL directly in the framework config:      export   default   defineNuxtConfig  ({\n     modules: [  'nuxtjs-drupal-ce'  ],\n     drupalCe: {\n       drupalBaseUrl:   'https://dev-your-drupal-site.pantheonsite.io'  ,\n     },\n   })\n     NEXT_PUBLIC_DRUPAL_BASE_URL  =  https  :  //dev-your-drupal-site.pantheonsite.io\n   For Nuxt, all   nuxtjs-drupal-ce  options can be overridden at runtime via   NUXT_PUBLIC_DRUPAL_CE_*  environment variables. See the   nuxtjs-drupal-ce documentation  for details.  Step 3: Push to Pantheon  Push your frontend code to the GitHub repo Pantheon created:     cd   my-frontend\n   rm   -rf   .git\n   git   init   &&   git   add   -A   &&   git   commit   -m   \"Initial deploy\"\n   git   remote   add   origin   git@github.com:your-org/your-pantheon-repo.git\n   git   branch   -m   main\n   git   push   --force   origin   main\n  Step 4: Wait for the build  Pantheon builds automatically on push. This typically takes 5–10 minutes.  You can check deployment status via the GitHub API:     gh   api   repos/your-org/your-repo/deployments   --jq   '.[0].statuses_url'   |   xargs   gh   api   --jq   '.[0].state'\n  Step 5: Verify  Visit   https://dev-your-frontend-site.pantheonsite.io/ . You may need to click through Pantheon's sandbox page on first visit. Your Drupal content should render through the frontend.  Node.js version  Pantheon auto-detects the Node.js version from the   engines  field in   package.json . If not specified, it defaults to Node.js LTS (currently v22).     {\n     \"engines\"  : {\n       \"node\"  :   \">=22\"\n     }\n   }\n  html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}",1775559438847]