---
url: 'https://dxpr.com/pt-pt/hc/documentation/learn-dxpr-builder/development/custom-elements'
title: 'Criar elementos personalizados | DXPR'
author:
  name: Jurriaan
  url: 'https://dxpr.com/users/jurriaan'
date: '2026-10-24T11:47:46+00:00'
copyright: 'Copyright DXPR. All rights reserved.'
type: article
summary: |-
  Cada elemento do DXPR Builder é um objeto JavaScript empurrado para
  window.dxprBuilder.dxpr_elements. O editor transforma cada objeto
  numa classe de elemento com os separadores Style e Animation já
  anexados. Esta página mostra como os elementos incluídos se definem em
  dxpr_builder/dxpr_elements.js, como um módulo adiciona a própria
  definição ao editor, e como fica o HTML resultante.
  Não há modelos Twig de servidor por elemento; os elementos
  apresentam-se no navegador.
tags:
  - 'Bouw erop voort'
image: 'https://dxpr.com/themes/custom/dxpr_com/images/dxpr-share-card.jpg'
published: true
og:
  site_name: DXPR
  updated_time: '2026-10-24T11:47:46+0000'
  'image:alt': 'DXPR, powered by Drupal: AI-powered Drupal for marketers.'
schema:
  '@context': 'https://schema.org'
  '@graph':
    -
      mainEntity: {  }
    -
      '@type': TechArticle
      headline: 'Criar elementos personalizados'
      description: |-
        Cada elemento do DXPR Builder é um objeto JavaScript empurrado para
        window.dxprBuilder.dxpr_elements. O editor transforma cada objeto
        numa classe de elemento com os separadores Style e Animation já
        anexados. Esta página mostra como os elementos incluídos se definem em
        dxpr_builder/dxpr_elements.js, como um módulo adiciona a própria
        definição ao editor, e como fica o HTML resultante.
        Não há modelos Twig de servidor por elemento; os elementos
        apresentam-se no navegador.
      image:
        '@type': ImageObject
        url: 'https://dxpr.com/themes/custom/dxpr_com/images/dxpr-share-card.jpg'
        width: '1200'
        height: '630'
      datePublished: '2026-10-24T11:47:46+0000'
      dateModified: '2026-10-24T11:47:46+0000'
      author:
        '@type': Organization
        '@id': 'https://dxpr.com/#organization'
        name: DXPR
        url: 'https://dxpr.com/'
        logo:
          '@type': ImageObject
          url: 'https://dxpr.com/themes/custom/dxpr_com/dxpr-logo-dark.svg'
          width: '1348'
          height: '501'
      publisher:
        '@type': Organization
        '@id': 'https://dxpr.com/#organization'
        name: DXPR
        url: 'https://dxpr.com/'
        logo:
          '@type': ImageObject
          url: 'https://dxpr.com/themes/custom/dxpr_com/dxpr-logo-dark.svg'
          width: '1348'
          height: '501'
      mainEntityOfPage: 'https://dxpr.com/pt-pt/hc/documentation/learn-dxpr-builder/development/custom-elements'
      articleSection: 'Bouw erop voort'
    -
      '@type': WebPage
      '@id': 'https://dxpr.com/pt-pt/hc/documentation/learn-dxpr-builder/development/custom-elements'
      description: |-
        Cada elemento do DXPR Builder é um objeto JavaScript empurrado para
        window.dxprBuilder.dxpr_elements. O editor transforma cada objeto
        numa classe de elemento com os separadores Style e Animation já
        anexados. Esta página mostra como os elementos incluídos se definem em
        dxpr_builder/dxpr_elements.js, como um módulo adiciona a própria
        definição ao editor, e como fica o HTML resultante.
        Não há modelos Twig de servidor por elemento; os elementos
        apresentam-se no navegador.
      breadcrumb:
        '@type': BreadcrumbList
        itemListElement:
          -
            '@type': ListItem
            position: 1
            name: Início
            item: 'https://dxpr.com/pt-pt'
      publisher:
        '@type': Organization
        '@id': 'https://dxpr.com/#organization'
        name: DXPR
      inLanguage: pt-pt
---
[Help Center](/pt-pt/node/75)/[Documentation](/pt-pt/hc/documentation) /[Learn DXPR Builder](/hc/documentation/learn-dxpr-builder) /[Extend](/hc/documentation/learn-dxpr-builder/extend) /[Bouw erop voort](/hc/documentation/learn-dxpr-builder/extend/build-on-it) # Criar elementos personalizados.

 Learn DXPR BuilderExtendBouw erop voort

   ## In this guide

 Related guides

- [Referência da API de hooks](/pt-pt/hc/documentation/learn-dxpr-builder/development/hooks-api)
- [Arquitetura](/pt-pt/hc/documentation/learn-dxpr-builder/development/architecture)

Cada elemento do DXPR Builder é um objeto JavaScript empurrado para `window.dxprBuilder.dxpr_elements`. O editor transforma cada objeto numa classe de elemento com os separadores Style e Animation já anexados. Esta página mostra como os elementos incluídos se definem em `dxpr_builder/dxpr_elements.js`, como um módulo adiciona a própria definição ao editor, e como fica o HTML resultante. Não há modelos Twig de servidor por elemento; os elementos apresentam-se no navegador.

## Como o editor regista elementos

O editor carrega seis scripts por esta ordem, definidos em `dxpr_builder_library_info_build()` em `dxpr_builder.module` como a biblioteca `dxpr_builder/editor.builder`:

1. `dxpr_templates.js`: modelos twig.js do lado do cliente compilados de `dxpr_builder/templates/`.
2. `dxpr_global.js`: auxiliares partilhados e a integração com CKEditor 5.
3. `dxpr_events.js`
4. `dxpr_param_types.js`: empurra um objeto por tipo de entrada para `window.dxprBuilder.dxpr_param_types`.
5. `dxpr_elements.js`: cria o array `window.dxprBuilder.dxpr_elements`e empurra uma definição por elemento.
6. `dxpr_builder.js`: o editor. Quando este ficheiro executa, chama `create_dxpr_elements()`, que percorre `window.dxprBuilder.dxpr_elements` e para cada definição:
    - chama `register_animated_element(base, is_container, Class)`, para a classe estender `AnimatedElement` (separador Style, separador Animation, HTML ID, classes HTML e parâmetros de colocação);
    - anexa os parâmetros herdados aos `params` da definição;
    - converte cada parâmetro através de `make_param_type()`, que compara `param.type` com os tipos de parâmetro registados;
    - mistura as propriedades da definição no protótipo da classe.

Uma definição tem por isso de estar no array depois de `dxpr_elements.js` correr e antes de `dxpr_builder.js` correr. Os seis ficheiros carregam com o atributo `defer`, por isso a ordem dos script tags no documento é a ordem de execução.

## A definição de elemento

Este é o elemento Alert de `dxpr_builder/dxpr_elements.js`(origem: `dxpr_builder/build/dxpr-elements/elements/az_alert.js`), reduzido às propriedades de que cada elemento precisa. O original também define `el_class`, um manipulador `onCancel` e um ouvinte `focusout`.

```javascript
window.dxprBuilder.dxpr_elements.push({
  base: "az_alert",
  name: Drupal.t("Alert"),
  nameEn: "Alert",
  icon: "az-custom-icon az-alert-icon",
  largeSettingsWindow: true,
  hidden: false,
  params: [
    {
      type: "textarea",
      heading: Drupal.t("Message"),
      param_name: "content",
      value: Drupal.t(
        "This is a placeholder text. Your actual content will go here. Edit this to include your own information.",
      ),
    },
    {
      type: "dropdown",
      heading: Drupal.t("Type"),
      param_name: "type",
      description: Drupal.t("Select message type."),
      getText: (opt) => opt.text,
      getValue: (opt) => opt.value,
      getDefault: (param) => param.value["alert-success"].value,
      value: {
        "alert-success": { text: Drupal.t("Success"), value: "alert-success" },
        "alert-info": { text: Drupal.t("Info"), value: "alert-info" },
        "alert-warning": { text: Drupal.t("Warning"), value: "alert-warning" },
        "alert-danger": { text: Drupal.t("Danger"), value: "alert-danger" },
      },
      passthrough: true,
    },
  ],
  show_settings_on_create: true,
  has_content: true,
  render(...args) {
    const state = {
      class: `az-element az-alert alert ${this.attrs.type} ${this.get_el_classes()} ${this.get_content_classes()}`,
      style: this.attrs.style,
      message: this.attrs.content,
    };
    this.dom_element = this.baseclass.prototype.render_template(
      "elements/alert/alert",
      state,
    );
    this.baseclass.prototype.render.apply(this, args);
  },
  save_history() {
    const container = this.get_my_container();
    container.save_container_history(Drupal.t("Edit alert"));
  },
});

```

| Property | Purpose |
|---|---|
| `base` | Nome de sistema. Escreve-se no HTML guardado como `data-azb="az_alert"` e usa-se para encontrar a classe quando a página é analisada outra vez. Mantenha o prefixo `az_`. |
| `name`, `nameEn` | Etiqueta no seletor de elementos e a forma não traduzida. |
| `icon` | Classes CSS para o ícone do seletor. Os ícones incluídos definem-se em `dxpr_builder/sass/dxpr-builder-backend/components/_custom-icons.scss`; um elemento personalizado precisa do próprio CSS para a classe de ícone. |
| `category` | Separador do seletor. Os elementos de esquema usam `Drupal.t("Layout")`; blocos e vistas usam `"CMS"`. Omita para o separador de conteúdo predefinido. |
| `is_container` | `true` quando o elemento contém outros elementos. |
| `largeSettingsWindow` | Abre o diálogo de definições no tamanho maior. |
| `hidden` | Esconde o elemento do seletor mantendo-o apresentável. |
| `params` | Definições mostradas no diálogo. Ver abaixo. |
| `show_settings_on_create` | Abre o diálogo de definições assim que o elemento é largado. |
| `has_content` | O elemento tem uma área de conteúdo editável (`dom_content_element`). |
| `render(...args)` | Constrói `this.dom_element` a partir de `this.attrs` e depois chama o `render` base. |
| `save_history()` | Empurra uma entrada de anulação com etiqueta. |
| `parse_attrs_from_dom(element)` | Opcional. Lê valores de parâmetro de volta da marcação guardada, usado com `skip_data_azb` e `skip_params` por elementos como Image que guardam valores nos atributos `<img>` em vez de `data-azat-*`. |

### Parâmetros

Cada entrada em `params` tem:

| Key | Meaning |
|---|---|
| `type` | Um dos tipos de parâmetro registados (próxima secção). |
| `heading` | Etiqueta do campo. |
| `param_name` | Chave em `this.attrs` e, no HTML guardado, o atributo `data-azat-<param_name>`. `content` é especial: é o corpo do elemento, não um atributo. |
| `value` | Valor predefinido. Para `dropdown` é um objeto de opções com retornos `getText`, `getValue` e `getDefault`. |
| `description` | Texto de ajuda sob o campo. |
| `tab` | Agrupa o campo num acordeão nomeado, por exemplo `Drupal.t("SEO")`. |
| `can_be_empty` | Guarda uma cadeia vazia em vez de largar o atributo. |
| `safe` | Omite a codificação de URL do valor guardado. |

Os tipos de parâmetro são os valores `type` empurrados para `window.dxprBuilder.dxpr_param_types` em `dxpr_builder/dxpr_param_types.js`: `boxmodel`, `checkbox`, `checkboxes`, `colorpicker`, `datetime`, `dropdown`, `dxb_slider`, `html`, `icon`, `image`, `images`, `link`, `links`, `numericfield`, `row_layout`, `saved_datetime`, `social_links`, `textarea`, `textfield` e `video`. Um tipo sem registo recua para uma entrada de texto simples (`BaseParamType`).

Não reutilize um `param_name` que cada elemento herda, como `color`, `background`, `el_class`, `hash` ou os nomes de animação `an_*`. O separador Style já detém `color`, por isso um segundo parâmetro com esse nome nunca é escrito em `data-azat-color`.

### O que fica guardado

`update_data()` em `dxpr_builder.js` escreve o elemento em HTML:

- `data-azb="<base>"` no elemento raiz;
- `data-azat-<param_name>="<value>"` para cada parâmetro cujo valor difere da predefinição, codificado para URL salvo se o parâmetro define `safe: true`;
- os parâmetros do separador Style como `style` em linha e classes, nunca como atributos `data-azat-*`;
- `data-azcnt="true"` no elemento de conteúdo quando `has_content` está definido.

Os visitantes sem editor recebem este HTML sem os atributos `data-az*`: `DxprBuilderService::parseDocumentForCleanup()`remove-os, exceto uma lista fixa que mantém em elementos animados e em elementos dinâmicos incluídos como Carousel. Se o elemento precisa de JavaScript ou CSS para visitantes, ponha um atributo `data-dxpr-builder-libraries="<key>"` na raiz: `parseDocumentForTemplateLibrary()` anexa `dxpr_builder/elements.<key>` para cada chave sem barra. As chaves são as bibliotecas `elements.*` em `dxpr_builder.libraries.yml`; uma chave com barra só é aceite quando é a `library` de um conjunto de ícones do registo.

## Exemplo mínimo funcional

O exemplo adiciona um elemento "Notice" que apresenta um parágrafo com uma cor escolhida. Constrói o DOM diretamente porque os modelos twig.js compilados em `dxpr_templates.js` fazem parte do pacote do editor e não podem ser estendidos por outro módulo.

1. Crie `mymodule/js/notice-element.js`:

    ```javascript
    window.dxprBuilder.dxpr_elements.push({
      base: "az_notice",
      name: Drupal.t("Notice"),
      nameEn: "Notice",
      icon: "az-custom-icon az-alert-icon",
      params: [
        {
          type: "textfield",
          heading: Drupal.t("Text"),
          param_name: "text",
          value: Drupal.t("Notice text"),
        },
        {
          type: "colorpicker",
          heading: Drupal.t("Colour"),
          param_name: "notice_color",
          value: "#0d6efd",
        },
      ],
      show_settings_on_create: true,
      render(...args) {
        const el = document.createElement("div");
        el.className = `az-element az-notice ${this.get_el_classes()}`;
        if (this.attrs.style) {
          el.setAttribute("style", this.attrs.style);
        }
        const p = document.createElement("p");
        p.style.color = this.attrs.notice_color;
        p.textContent = this.attrs.text;
        el.appendChild(p);
        this.dom_element = el;
        this.baseclass.prototype.render.apply(this, args);
      },
      save_history() {
        this.get_my_container().save_container_history(Drupal.t("Edit notice"));
      },
    });

    ```
2. Insira o ficheiro na biblioteca do editor entre `dxpr_elements.js` (peso `-4`) e `dxpr_builder.js` (peso `-3`) em `mymodule.module`:

    ```php
    /**
     * Implements hook_library_info_alter().
     */
    function mymodule_library_info_alter(array &$libraries, string $extension): void {
      if ($extension === 'dxpr_builder' && isset($libraries['editor.builder'])) {
        $path = '/' . \Drupal::service('extension.list.module')->getPath('mymodule');
        $libraries['editor.builder']['js'][$path . '/js/notice-element.js'] = [
          'weight' => -3.5,
          'preprocess' => FALSE,
          'attributes' => ['defer' => TRUE],
        ];
      }
    }

    ```

    `preprocess: FALSE` e `defer` correspondem às entradas que o módulo define para os próprios ficheiros, por isso o ficheiro mantém o lugar na sequência quer os recursos do editor venham da CDN ou de uma compilação local.
3. Limpe a cache e abra uma página do construtor:

    ```bash
    drush cr

    ```
4. Adicione o elemento a partir do seletor, defina o texto e a cor, e guarde. O campo guarda:

    ```html
    <div class="az-element az-notice" id="..." data-azb="az_notice"
         data-azat-text="Hello" data-azat-notice_color="%23198754">
      <p style="color: #198754;">Hello</p>
    </div>

    ```

    Um visitante recebe a mesma marcação sem os atributos `data-az*`. O parágrafo mantém a cor em linha, por isso não é precisa biblioteca de visitantes para este elemento.

## Limites a conhecer

- **Profiles do not list custom elements.** A lista de verificação de elementos num perfil do construtor vem de uma lista fixa em `src/Form/DxprBuilderProfileForm.php` e `src/Service/Handler/ProfileHandler.php`. Elementos fora dessa lista nunca são escondidos por um perfil.
- **Icons for the picker** precisam de CSS do módulo; as classes `az-custom-icon` incluídas no construtor abrangem apenas os elementos incluídos.
- **`DxprBuilderService::getDxprElementsFolders()`** e o `hook_dxpr_builder_elements_folders_alter()` devolvem uma lista de pastas `elements` em temas, mas nada no editor lê essa lista. Não é uma rota de registo.
- **Style and Animation tabs** são adicionados por `register_animated_element()`; não redefina esses parâmetros.

## O que se segue?

- [API de hooks](/hc/documentation/learn-dxpr-builder/development/hooks-api) para os hooks PHP que adicionam classes utilitárias e conjuntos de ícones.
- [Arquitetura](/hc/documentation/learn-dxpr-builder/development/architecture) para saber como o editor e o formatador de campo combinam.