---
url: 'https://dxpr.com/de/hc/documentation/learn-dxpr-builder/development/custom-elements'
title: 'Eigene Elemente erstellen | DXPR'
author:
  name: Jurriaan
  url: 'https://dxpr.com/users/jurriaan'
date: '2026-10-24T04:04:57+00:00'
updated: '2026-10-24T09:09:48+00:00'
copyright: 'Copyright DXPR. All rights reserved.'
type: article
summary: |-
  Jedes DXPR-Builder-Element ist ein JavaScript-Objekt, das auf
  window.dxprBuilder.dxpr_elements gepusht wird. Der Editor macht
  aus jedem Objekt eine Elementklasse, mit bereits angehängten Tabs Style
  und Animation. Diese Seite zeigt, wie die mitgebrachten Elemente in
  dxpr_builder/dxpr_elements.js definiert sind, wie ein Modul eine
  eigene Definition in den Editor einbringt und wie das Ergebnis-HTML
  aussieht. Es gibt keine serverseitigen Twig-Vorlagen pro Element;
  Elemente rendern im Browser.
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-24T09:09:48+0000'
  'image:alt': 'DXPR, powered by Drupal: AI-powered Drupal for marketers.'
schema:
  '@context': 'https://schema.org'
  '@graph':
    -
      mainEntity: {  }
    -
      '@type': TechArticle
      headline: 'Eigene Elemente erstellen'
      description: |-
        Jedes DXPR-Builder-Element ist ein JavaScript-Objekt, das auf
        window.dxprBuilder.dxpr_elements gepusht wird. Der Editor macht
        aus jedem Objekt eine Elementklasse, mit bereits angehängten Tabs Style
        und Animation. Diese Seite zeigt, wie die mitgebrachten Elemente in
        dxpr_builder/dxpr_elements.js definiert sind, wie ein Modul eine
        eigene Definition in den Editor einbringt und wie das Ergebnis-HTML
        aussieht. Es gibt keine serverseitigen Twig-Vorlagen pro Element;
        Elemente rendern im Browser.
      image:
        '@type': ImageObject
        url: 'https://dxpr.com/themes/custom/dxpr_com/images/dxpr-share-card.jpg'
        width: '1200'
        height: '630'
      datePublished: '2026-10-24T04:04:57+0000'
      dateModified: '2026-10-24T09:09:48+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/de/hc/documentation/learn-dxpr-builder/development/custom-elements'
      articleSection: 'Bouw erop voort'
    -
      '@type': WebPage
      '@id': 'https://dxpr.com/de/hc/documentation/learn-dxpr-builder/development/custom-elements'
      description: |-
        Jedes DXPR-Builder-Element ist ein JavaScript-Objekt, das auf
        window.dxprBuilder.dxpr_elements gepusht wird. Der Editor macht
        aus jedem Objekt eine Elementklasse, mit bereits angehängten Tabs Style
        und Animation. Diese Seite zeigt, wie die mitgebrachten Elemente in
        dxpr_builder/dxpr_elements.js definiert sind, wie ein Modul eine
        eigene Definition in den Editor einbringt und wie das Ergebnis-HTML
        aussieht. Es gibt keine serverseitigen Twig-Vorlagen pro Element;
        Elemente rendern im Browser.
      breadcrumb:
        '@type': BreadcrumbList
        itemListElement:
          -
            '@type': ListItem
            position: 1
            name: Startseite
            item: 'https://dxpr.com/de'
      publisher:
        '@type': Organization
        '@id': 'https://dxpr.com/#organization'
        name: DXPR
      inLanguage: de
---
[Help Center](/de/hc)/[Documentation](/de/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) # Eigene Elemente erstellen.

 Learn DXPR BuilderExtendBouw erop voort

   ## In this guide

 Related guides

- [Hooks-API-Referenz](/de/hc/documentation/learn-dxpr-builder/development/hooks-api)
- [Architektur](/de/hc/documentation/learn-dxpr-builder/development/architecture)

Jedes DXPR-Builder-Element ist ein JavaScript-Objekt, das auf `window.dxprBuilder.dxpr_elements` gepusht wird. Der Editor macht aus jedem Objekt eine Elementklasse, mit bereits angehängten Tabs Style und Animation. Diese Seite zeigt, wie die mitgebrachten Elemente in `dxpr_builder/dxpr_elements.js` definiert sind, wie ein Modul eine eigene Definition in den Editor einbringt und wie das Ergebnis-HTML aussieht. Es gibt keine serverseitigen Twig-Vorlagen pro Element; Elemente rendern im Browser.

## Wie der Editor Elemente registriert

Der Editor lädt sechs Skripte in dieser Reihenfolge, definiert in `dxpr_builder_library_info_build()` in `dxpr_builder.module` als Bibliothek `dxpr_builder/editor.builder`:

1. `dxpr_templates.js`: clientseitige twig.js-Vorlagen, kompiliert aus `dxpr_builder/templates/`.
2. `dxpr_global.js`: geteilte Helfer und die CKEditor-5-Integration.
3. `dxpr_events.js`
4. `dxpr_param_types.js`: pusht je ein Objekt pro Eingabetyp auf `window.dxprBuilder.dxpr_param_types`.
5. `dxpr_elements.js`: erzeugt das Array `window.dxprBuilder.dxpr_elements`und pusht eine Definition pro Element.
6. `dxpr_builder.js`: der Editor. Wenn diese Datei ausführt, ruft sie `create_dxpr_elements()` auf, das über `window.dxprBuilder.dxpr_elements` loopt und pro Definition:
    - ruft `register_animated_element(base, is_container, Class)` auf, sodass die Klasse `AnimatedElement` erweitert (Tab Style, Tab Animation, HTML-ID, HTML-Klassen und Platzierungsparameter);
    - die geerbten Parameter an die `params` der Definition anhängt;
    - jeden Parameter durch `make_param_type()` wandelt, das `param.type` gegen die registrierten Parametertypen matcht;
    - die Eigenschaften der Definition in den Klassenprototyp mischt.

Eine Definition muss daher nach `dxpr_elements.js` und vor `dxpr_builder.js` auf dem Array liegen. Alle sechs Dateien laden mit dem `defer`-Attribut, daher ist die Dokumentreihenfolge der Skript-Tags die Ausführungsreihenfolge.

## Die Elementdefinition

Dies ist das Alert-Element aus `dxpr_builder/dxpr_elements.js`(Quelle: `dxpr_builder/build/dxpr-elements/elements/az_alert.js`), gestutzt auf die Eigenschaften, die jedes Element braucht. Das Original setzt außerdem `el_class`, einen `onCancel`-Handler und einen `focusout`-Listener.

```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"));
  },
});

```

| Eigenschaft | Zweck |
|---|---|
| `base` | Systemname. Er wird als `data-azb="az_alert"` in das gespeicherte HTML geschrieben und genutzt, um die Klasse zu finden, wenn die Seite erneut geparst wird. Den `az_`-Präfix behalten. |
| `name`, `nameEn` | Bezeichnung in der Elementauswahl und ihre unübersetzte Form. |
| `icon` | CSS-Klassen für das Auswahl-Icon. Die mitgebrachten Icons sind in `dxpr_builder/sass/dxpr-builder-backend/components/_custom-icons.scss` definiert; ein eigenes Element braucht eigenes CSS für seine Icon-Klasse. |
| `category` | Auswahl-Tab. Die Layout-Elemente nutzen `Drupal.t("Layout")`; Blöcke und Ansichten nutzen `"CMS"`. Weglassen für den Standard-Inhalts-Tab. |
| `is_container` | `true`, wenn das Element andere Elemente hält. |
| `largeSettingsWindow` | Öffnet den Einstellungsdialog in der größeren Größe. |
| `hidden` | Verbirgt das Element vor der Auswahl, hält es aber renderbar. |
| `params` | Einstellungen, die im Dialog gezeigt werden. Siehe unten. |
| `show_settings_on_create` | Öffnet den Einstellungsdialog, sobald das Element abgelegt wird. |
| `has_content` | Das Element hat einen bearbeitbaren Inhaltsbereich (`dom_content_element`). |
| `render(...args)` | Baut `this.dom_element` aus `this.attrs` und ruft dann das Basis-`render` auf. |
| `save_history()` | Pusht einen Rückgängig-Eintrag mit Bezeichnung. |
| `parse_attrs_from_dom(element)` | Optional. Liest Parameterwerte aus gespeichertem Markup zurück, genutzt zusammen mit `skip_data_azb` und `skip_params` von Elementen wie Image, die Werte in den `<img>`-Attributen statt `data-azat-*` speichern. |

### Parameter

Jeder Eintrag in `params` hat:

| Schlüssel | Bedeutung |
|---|---|
| `type` | Einer der registrierten Parametertypen (nächster Abschnitt). |
| `heading` | Feldbezeichnung. |
| `param_name` | Schlüssel in `this.attrs` und, im gespeicherten HTML, das Attribut `data-azat-<param_name>`. `content` ist besonders: Es ist der Element-Body, kein Attribut. |
| `value` | Standardwert. Für `dropdown` ist es ein Optionsobjekt mit `getText`-, `getValue`- und `getDefault`-Callbacks. |
| `description` | Hilfetext unter dem Feld. |
| `tab` | Gruppiert das Feld in ein benanntes Akkordeon, zum Beispiel `Drupal.t("SEO")`. |
| `can_be_empty` | Leere Zeichenkette speichern, statt das Attribut zu droppen. |
| `safe` | URL-Codierung des gespeicherten Werts überspringen. |

Die Parametertypen sind die `type`-Werte, die in `dxpr_builder/dxpr_param_types.js` auf `window.dxprBuilder.dxpr_param_types` gepusht werden: `boxmodel`, `checkbox`, `checkboxes`, `colorpicker`, `datetime`, `dropdown`, `dxb_slider`, `html`, `icon`, `image`, `images`, `link`, `links`, `numericfield`, `row_layout`, `saved_datetime`, `social_links`, `textarea`, `textfield` und `video`. Ein Typ, den Sie nicht registrieren, fällt auf eine schlichte Texteingabe zurück (`BaseParamType`).

Nutzen Sie keinen `param_name` wieder, den jedes Element erbt, etwa `color`, `background`, `el_class`, `hash` oder die `an_*`-Animationsnamen. Der Tab Style besitzt `color` bereits, daher wird ein zweiter Parameter mit diesem Namen nie nach `data-azat-color` geschrieben.

### Was gespeichert wird

`update_data()` in `dxpr_builder.js` schreibt das Element nach HTML:

- `data-azb="<base>"` auf dem Wurzelelement;
- `data-azat-<param_name>="<value>"` für jeden Parameter, dessen Wert vom Standard abweicht, URL-codiert, außer der Parameter setzt `safe: true`;
- die Style-Tab-Parameter als Inline-`style` und Klassen, nie als `data-azat-*`-Attribute;
- `data-azcnt="true"` auf dem Inhaltselement, wenn `has_content`gesetzt ist.

Betrachtende, die den Editor nicht erhalten, bekommen dieses HTML ohne seine `data-az*`-Attribute: `DxprBuilderService::parseDocumentForCleanup()`streift sie, außer einer festen Liste, die es auf animierten Elementen und auf eingebauten dynamischen Elementen wie Carousel behält. Wenn das Element JavaScript oder CSS für Besuchende braucht, legen Sie ein `data-dxpr-builder-libraries="<key>"`-Attribut auf seine Wurzel: `parseDocumentForTemplateLibrary()` hängt `dxpr_builder/elements.<key>` für jeden Schlüssel ohne Schrägstrich an. Die Schlüssel sind die `elements.*`-Bibliotheken in `dxpr_builder.libraries.yml`; ein Schlüssel mit Schrägstrich gilt nur, wenn er die `library` eines registrierten Icon-Sets ist.

## Minimal lauffähiges Beispiel

Das Beispiel fügt ein „Notice“-Element hinzu, das einen Absatz mit gewählter Farbe rendert. Es baut sein DOM direkt, weil die kompilierten twig.js-Vorlagen in `dxpr_templates.js` Teil des Editor-Bundles sind und von einem anderen Modul nicht erweitert werden können.

1. Erstellen Sie `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. Fügen Sie die Datei zwischen `dxpr_elements.js` (Gewicht `-4`) und `dxpr_builder.js` (Gewicht `-3`) in die Editor-Bibliothek ein, in `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` und `defer` passen zu den Einträgen, die das Modul für seine eigenen Dateien definiert, daher behält die Datei ihren Platz in der Reihenfolge, ob Editor-Assets vom CDN oder aus einem lokalen Build kommen.
3. Leeren Sie den Cache und öffnen Sie eine Builder-Seite:

    ```bash
    drush cr

    ```
4. Fügen Sie das Element aus der Auswahl hinzu, setzen Sie Text und Farbe und speichern Sie. Das Feld speichert:

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

    ```

    Gäste erhalten dasselbe Markup ohne die `data-az*`-Attribute. Der Absatz behält seine Inline-Farbe, daher braucht dieses Element keine Besucherbibliothek.

## Zu kennende Grenzen

- **Profile listen eigene Elemente nicht.** Die Element-Checkliste in einem Builder-Profil stammt aus einer festen Liste in `src/Form/DxprBuilderProfileForm.php` und `src/Service/Handler/ProfileHandler.php`. Elemente außerhalb dieser Liste verbirgt kein Profil je.
- **Icons für die Auswahl** brauchen CSS aus Ihrem Modul; die `az-custom-icon`-Klassen des Builders decken nur die mitgebrachten Elemente ab.
- **`DxprBuilderService::getDxprElementsFolders()`** und sein `hook_dxpr_builder_elements_folders_alter()` liefern eine Liste von `elements`-Ordnern in Themes, aber nichts im Editor liest diese Liste. Es ist keine Registrierungsroute.
- **Style- und Animation-Tabs** werden von `register_animated_element()` für Sie hinzugefügt; definieren Sie diese Parameter nicht neu.

## Wie geht es weiter?

- [Hooks-API](/de/hc/documentation/learn-dxpr-builder/development/hooks-api) für die PHP-Hooks, die Dienstklassen und Icon-Sets hinzufügen.
- [Architektur](/de/hc/documentation/learn-dxpr-builder/development/architecture): wie Editor und Feld-Formatierer zusammenpassen.