Breaking: #107443 - Migrate Modal component from Bootstrap to native dialog 

See forge#107443

Description 

The TYPO3 Modal component has been migrated from Bootstrap's modal implementation to use the native HTML <dialog> element. This improves accessibility, reduces bundle size, and removes the dependency on Bootstrap's JavaScript for modal functionality.

As part of this migration, Bootstrap's native modal events (such as show.bs.modal, shown.bs.modal, hide.bs.modal, and hidden.bs.modal) are no longer dispatched.

Likewise, direct Bootstrap modal API usage (for example new Modal() from Bootstrap or $(element).modal()) is no longer supported.

Impact 

Bootstrap modal events ( *.bs.modal) are no longer available.

Extensions listening to these events must migrate to TYPO3's custom modal events.

The Modal component now uses the native <dialog> element with updated CSS classes and DOM structure.

Any direct manipulation of Bootstrap modal APIs will no longer work.

Extensions using data-bs-toggle="modal", data-bs-content="...", or data-bs-target attributes to trigger modals must migrate to TYPO3's Modal API.

Affected installations 

All installations with custom extensions that:

  • Listen to Bootstrap modal events ( show.bs.modal, shown.bs.modal, hide.bs.modal, hidden.bs.modal)
  • Use Bootstrap's modal JavaScript API directly (for example new bootstrap.Modal())
  • Use jQuery to control modals (for example $(element).modal('show'))
  • Use data-bs-toggle="modal" or data-bs-content="..." attributes
  • Manipulate modal DOM structures or classes expecting Bootstrap markup

Migration 

Event migration 

Replace Bootstrap modal event listeners with TYPO3's custom modal events. Event listeners must be attached to the modal instance returned by the Modal API, not queried from the DOM.

Before:

const modalElement = document.querySelector('.modal');
modalElement.addEventListener('show.bs.modal', (event) => {
  console.log('Modal is about to be shown');
});
modalElement.addEventListener('shown.bs.modal', (event) => {
  console.log('Modal is now visible');
});
modalElement.addEventListener('hide.bs.modal', (event) => {
  console.log('Modal is about to be hidden');
});
modalElement.addEventListener('hidden.bs.modal', (event) => {
  console.log('Modal is now hidden');
});
Copied!

After:

import Modal from '@typo3/backend/modal';
import Severity from '@typo3/backend/severity';

const modal = Modal.show(
  'My Modal Title',
  'This is the modal content',
  Severity.info
);

modal.addEventListener('typo3-modal-show', (event) => {
  console.log('Modal is about to be shown');
});
modal.addEventListener('typo3-modal-shown', (event) => {
  console.log('Modal is now visible');
});
modal.addEventListener('typo3-modal-hide', (event) => {
  console.log('Modal is about to be hidden');
});
modal.addEventListener('typo3-modal-hidden', (event) => {
  console.log('Modal is now hidden');
});
Copied!

Bootstrap API migration 

Replace Bootstrap modal API calls with TYPO3's Modal API.

Do not instantiate Bootstrap modals or manipulate modal DOM elements directly.

Before:

import { Modal } from 'bootstrap';

const modalElement = document.querySelector('.modal');
const bsModal = new Modal(modalElement);
bsModal.show();
bsModal.hide();
Copied!

After:

import Modal from '@typo3/backend/modal';
import Severity from '@typo3/backend/severity';

// Show a simple modal
Modal.show(
  'My Modal Title',
  'This is the modal content',
  Severity.info,
  [
    {
      text: 'Close',
      btnClass: 'btn-default',
      trigger: (event, modal) => modal.hideModal()
    }
  ]
);

// Dismiss the current modal
Modal.dismiss();
Copied!

Data attribute migration 

Replace Bootstrap's data-bs-toggle and data-bs-target attributes with TYPO3's modal trigger API.

Before:

<button type="button"
        data-bs-toggle="modal"
        data-bs-target="#myModal"
        data-bs-content="Are you sure?">
  Open Modal
</button>
Copied!

After:

<button type="button"
        class="t3js-modal-trigger"
        data-title="Confirmation"
        data-content="Are you sure?"
        data-severity="warning"
        data-button-close-text="Cancel"
        data-button-ok-text="Confirm">
  Open Modal
</button>
Copied!

Alternatively, use the JavaScript API directly:

import Modal from '@typo3/backend/modal';
import Severity from '@typo3/backend/severity';

document.querySelector('button').addEventListener('click', (event) => {
  Modal.confirm(
    'Confirmation',
    'Are you sure?',
    Severity.warning
  );
});
Copied!