---
url: 'https://dxpr.com/pl/hc/documentation/learn-dxpr-builder/development/custom-elements'
title: 'Tworzenie własnych elementów | DXPR'
author:
  name: Jurriaan
  url: 'https://dxpr.com/users/jurriaan'
date: '2026-10-24T11:38:30+00:00'
copyright: 'Copyright DXPR. All rights reserved.'
type: article
summary: |-
  Każdy element kreatora DXPR to obiekt JavaScript wepchnięty na
  window.dxprBuilder.dxpr_elements. Edytor zamienia każdy obiekt
  w klasę elementu z dołączonymi kartami Style i Animation. Ta strona pokazuje,
  jak zdefiniowane są dostarczone elementy w
  dxpr_builder/dxpr_elements.js, jak moduł dodaje własną
  definicję do edytora i jak wygląda wynikowy HTML.
  Nie ma szablonów Twig po stronie serwera dla elementu; elementy
  renderują się w przeglądarce.
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:38:30+0000'
  'image:alt': 'DXPR, powered by Drupal: AI-powered Drupal for marketers.'
schema:
  '@context': 'https://schema.org'
  '@graph':
    -
      mainEntity: {  }
    -
      '@type': TechArticle
      headline: 'Tworzenie własnych elementów'
      description: |-
        Każdy element kreatora DXPR to obiekt JavaScript wepchnięty na
        window.dxprBuilder.dxpr_elements. Edytor zamienia każdy obiekt
        w klasę elementu z dołączonymi kartami Style i Animation. Ta strona pokazuje,
        jak zdefiniowane są dostarczone elementy w
        dxpr_builder/dxpr_elements.js, jak moduł dodaje własną
        definicję do edytora i jak wygląda wynikowy HTML.
        Nie ma szablonów Twig po stronie serwera dla elementu; elementy
        renderują się w przeglądarce.
      image:
        '@type': ImageObject
        url: 'https://dxpr.com/themes/custom/dxpr_com/images/dxpr-share-card.jpg'
        width: '1200'
        height: '630'
      datePublished: '2026-10-24T11:38:30+0000'
      dateModified: '2026-10-24T11:38:30+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/pl/hc/documentation/learn-dxpr-builder/development/custom-elements'
      articleSection: 'Bouw erop voort'
    -
      '@type': WebPage
      '@id': 'https://dxpr.com/pl/hc/documentation/learn-dxpr-builder/development/custom-elements'
      description: |-
        Każdy element kreatora DXPR to obiekt JavaScript wepchnięty na
        window.dxprBuilder.dxpr_elements. Edytor zamienia każdy obiekt
        w klasę elementu z dołączonymi kartami Style i Animation. Ta strona pokazuje,
        jak zdefiniowane są dostarczone elementy w
        dxpr_builder/dxpr_elements.js, jak moduł dodaje własną
        definicję do edytora i jak wygląda wynikowy HTML.
        Nie ma szablonów Twig po stronie serwera dla elementu; elementy
        renderują się w przeglądarce.
      breadcrumb:
        '@type': BreadcrumbList
        itemListElement:
          -
            '@type': ListItem
            position: 1
            name: 'Strona Główna'
            item: 'https://dxpr.com/pl'
      publisher:
        '@type': Organization
        '@id': 'https://dxpr.com/#organization'
        name: DXPR
      inLanguage: pl
---
[Help Center](/pl/hc)/[Documentation](/pl/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) # Tworzenie własnych elementów.

 Learn DXPR BuilderExtendBouw erop voort

   ## In this guide

 Related guides

- [Dokumentacja hooków API](/pl/hc/documentation/learn-dxpr-builder/development/hooks-api)
- [Architektura](/pl/hc/documentation/learn-dxpr-builder/development/architecture)

Każdy element kreatora DXPR to obiekt JavaScript wepchnięty na `window.dxprBuilder.dxpr_elements`. Edytor zamienia każdy obiekt w klasę elementu z dołączonymi kartami Style i Animation. Ta strona pokazuje, jak zdefiniowane są dostarczone elementy w `dxpr_builder/dxpr_elements.js`, jak moduł dodaje własną definicję do edytora i jak wygląda wynikowy HTML. Nie ma szablonów Twig po stronie serwera dla elementu; elementy renderują się w przeglądarce.

## Jak edytor rejestruje elementy

Edytor wczytuje sześć skryptów w tej kolejności, zdefiniowanych w `dxpr_builder_library_info_build()` w `dxpr_builder.module` jako biblioteka `dxpr_builder/editor.builder`:

1. `dxpr_templates.js`: szablony twig.js po stronie klienta skompilowane z `dxpr_builder/templates/`.
2. `dxpr_global.js`: współdzielone helpery i integracja CKEditor 5.
3. `dxpr_events.js`
4. `dxpr_param_types.js`: wpycha jeden obiekt na typ wejścia na `window.dxprBuilder.dxpr_param_types`.
5. `dxpr_elements.js`: tworzy tablicę `window.dxprBuilder.dxpr_elements`i wpycha jedną definicję na element.
6. `dxpr_builder.js`: edytor. Gdy ten plik się wykona, wywołuje `create_dxpr_elements()`, które przechodzi pętlą `window.dxprBuilder.dxpr_elements` i dla każdej definicji:
    - wywołuje `register_animated_element(base, is_container, Class)`, więc klasa rozszerza `AnimatedElement` (karta Style, karta Animation, HTML ID, klasy HTML i parametry umiejscowienia);
    - dołącza odziedziczone parametry do `params` definicji;
    - konwertuje każdy parametr przez `make_param_type()`, które dopasowuje `param.type` do zarejestrowanych typów parametrów;
    - wmiesza właściwości definicji do prototypu klasy.

Definicja musi więc znaleźć się na tablicy po wykonaniu `dxpr_elements.js` i przed wykonaniem `dxpr_builder.js`. Wszystkie sześć plików ładuje się z atrybutem `defer`, więc kolejność dokumentów tagów script jest kolejnością wykonania.

## Definicja elementu

Tak wygląda element Alert z `dxpr_builder/dxpr_elements.js`(źródło: `dxpr_builder/build/dxpr-elements/elements/az_alert.js`), przycięty do właściwości potrzebnych każdemu elementowi. Oryginał ustawia też `el_class`, handler `onCancel` i listener `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"));
  },
});

```

| Właściwość | Przeznaczenie |
|---|---|
| `base` | Nazwa maszynowa. Zapisywana jest do zapisanego HTML jako `data-azb="az_alert"` i służy do znalezienia klasy, gdy strona jest ponownie parsowana. Zachowaj prefiks `az_`. |
| `name`, `nameEn` | Etykieta w wybieraku elementów i jej nieprzetłumaczona forma. |
| `icon` | Klasy CSS ikony wybieraka. Dostarczone ikony zdefiniowane są w `dxpr_builder/sass/dxpr-builder-backend/components/_custom-icons.scss`; własny element potrzebuje własnego CSS dla klasy ikony. |
| `category` | Karta wybieraka. Elementy układu używają `Drupal.t("Layout")`; bloki i widoki używają `"CMS"`. Pomiń dla domyślnej karty treści. |
| `is_container` | `true`, gdy element zawiera inne elementy. |
| `largeSettingsWindow` | Otwiera okno ustawień w większym rozmiarze. |
| `hidden` | Ukrywa element przed wybierakiem, zachowując jego renderowalność. |
| `params` | Ustawienia pokazywane w oknie. Zobacz poniżej. |
| `show_settings_on_create` | Otwiera okno ustawień, gdy tylko element zostanie upuszczony. |
| `has_content` | Element ma edytowalny obszar treści (`dom_content_element`). |
| `render(...args)` | Buduje `this.dom_element` z `this.attrs`, potem wywołuje bazowe `render`. |
| `save_history()` | Wpycha wpis cofania z etykietą. |
| `parse_attrs_from_dom(element)` | Opcjonalne. Odczytuje wartości parametrów z powrotem z zapisanego HTML, używane wraz z `skip_data_azb` i `skip_params` przez elementy takie jak Image, które przechowują wartości w atrybutach `<img>` zamiast `data-azat-*`. |

### Parametry

Każdy wpis w `params` ma:

| Klucz | Znaczenie |
|---|---|
| `type` | Jeden z zarejestrowanych typów parametrów (następna sekcja). |
| `heading` | Etykieta pola. |
| `param_name` | Klucz w `this.attrs` i, w zapisanym HTML, atrybut `data-azat-<param_name>`. `content` jest specjalne: to treść elementu, nie atrybut. |
| `value` | Wartość domyślna. Dla `dropdown` to obiekt opcji z callbackami `getText`, `getValue` i `getDefault`. |
| `description` | Tekst pomocy pod polem. |
| `tab` | Grupuje pole w nazwany akordeon, na przykład `Drupal.t("SEO")`. |
| `can_be_empty` | Przechowaj pusty ciąg zamiast porzucać atrybut. |
| `safe` | Pomiń kodowanie URL przechowywanej wartości. |

Typy parametrów to wartości `type` wepchnięte na `window.dxprBuilder.dxpr_param_types` w `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` i `video`. Typ, którego nie zarejestrujesz, wraca do zwykłego wejścia tekstowego (`BaseParamType`).

Nie używaj ponownie `param_name`, które dziedziczy każdy element, takiego jak `color`, `background`, `el_class`, `hash` albo nazwy animacji `an_*`. Karta Style już posiada `color`, więc drugi parametr o tej nazwie nigdy nie jest zapisywany do `data-azat-color`.

### Co się zapisuje

`update_data()` w `dxpr_builder.js` zapisuje element do HTML:

- `data-azb="<base>"` na elemencie głównym;
- `data-azat-<param_name>="<value>"` dla każdego parametru, którego wartość różni się od domyślnej, kodowane URL, chyba że parametr ustawia `safe: true`;
- parametry karty Style jako osadzone `style` i klasy, nigdy jako atrybuty `data-azat-*`;
- `data-azcnt="true"` na elemencie treści, gdy ustawiono `has_content`.

Odwiedzający bez edytora otrzymują ten HTML bez jego atrybutów `data-az*`: `DxprBuilderService::parseDocumentForCleanup()`usuwa je, poza stałą listą zachowywaną na elementach animowanych i na wbudowanych elementach dynamicznych takich jak Carousel. Jeśli element potrzebuje JavaScript albo CSS dla odwiedzających, umieść atrybut `data-dxpr-builder-libraries="<key>"` na jego elemencie głównym: `parseDocumentForTemplateLibrary()` dołącza `dxpr_builder/elements.<key>` dla każdego klucza bez ukośnika. Klucze to biblioteki `elements.*` w `dxpr_builder.libraries.yml`; klucz z ukośnikiem honorowany jest tylko, gdy jest `library` zarejestrowanego zestawu ikon.

## Minimalny działający przykład

Przykład dodaje element „Notice”, który renderuje akapit z wybranym kolorem. Buduje swój DOM bezpośrednio, ponieważ skompilowane szablony twig.js w `dxpr_templates.js` są częścią pakietu edytora i nie mogą być rozszerzane przez inny moduł.

1. Utwórz `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. Wstaw plik do biblioteki edytora między `dxpr_elements.js` (waga `-4`) a `dxpr_builder.js` (waga `-3`) w `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` i `defer` odpowiadają wpisom definiowanym przez moduł dla własnych plików, więc plik zachowuje swoje miejsce w sekwencji niezależnie od tego, czy pliki edytora pochodzą z CDN, czy z lokalnej kompilacji.
3. Wyczyść pamięć podręczną i otwórz stronę kreatora:

    ```bash
    drush cr

    ```
4. Dodaj element z wybieraka, ustaw jego tekst i kolor, i zapisz. Pole przechowuje:

    ```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>

    ```

    Odwiedzający dostaje ten sam HTML bez atrybutów `data-az*`. Akapit zachowuje swój osadzony kolor, więc ten element nie potrzebuje biblioteki dla odwiedzających.

## Ograniczenia, o których warto wiedzieć

- **Profile nie wymieniają własnych elementów.** Lista kontrolna elementów w profilu kreatora pochodzi ze stałej listy w `src/Form/DxprBuilderProfileForm.php` i `src/Service/Handler/ProfileHandler.php`. Elementy spoza tej listy nigdy nie są ukrywane przez profil.
- **Ikony dla wybieraka** potrzebują CSS z twojego modułu; klasy `az-custom-icon` dostarczane przez kreator obejmują tylko dostarczone elementy.
- **`DxprBuilderService::getDxprElementsFolders()`** i jego `hook_dxpr_builder_elements_folders_alter()` zwracają listę katalogów `elements` w motywach, ale nic w edytorze nie odczytuje tej listy. To nie jest trasa rejestracji.
- **Karty Style i Animation** dodawane są za ciebie przez `register_animated_element()`; nie redefiniuj tych parametrów.

## Co dalej?

- [Hooki API](/hc/documentation/learn-dxpr-builder/development/hooks-api) dla hooków PHP dodających klasy narzędziowe i zestawy ikon.
- [Architektura](/hc/documentation/learn-dxpr-builder/development/architecture) dla dopasowania edytora i formatera pola do siebie.