---
title: "Breaking: #107823 - Strict typing and API cleanup in backend template components"
manual: "TYPO3 Core Changelog"
version: "main"
permalink: "https://docs.typo3.org/permalink/changelog:breaking-107823-1730000000"
source: "Changelog/14.0/Breaking-107823-StrictTypingAndAPICleanupInBackendTemplateComponents.rst"
typo3-version: "14.0"
typo3-major: 14
type: "breaking"
issue: 107823
forge: "https://forge.typo3.org/issues/107823"
tags: ["Backend", "PHP-API", "NotScanned", "ext:backend"]
rendered: "2026-09-20T18:31:11+00:00"
---

# Breaking: #107823 - Strict typing and API cleanup in backend template components {#breaking-107823-1730000000}

See [forge#107823](https://forge.typo3.org/issues/107823)

## Description {#description}

The backend template components system (buttons, dropdown items, and menus) has
been modernized with strict type hints, consistent return types, and improved
architecture to enhance type safety and developer experience.

## Impact {#impact}

Extensions that implement or extend backend template components must verify
their type declarations and update any usage of changed methods.

### New ComponentInterface {#new-componentinterface}

A new `\TYPO3\CMS\Backend\Template\Components\ComponentInterface`
has been introduced as the parent interface for both
`ButtonInterface` and
`DropDownItemInterface`.
This unifies the common contract for all renderable backend components.

Both interfaces now extend
`ComponentInterface`,
which defines:

-   `isValid(): bool`
-   `getType(): string`
-   `render(): string`

Custom implementations of `ButtonInterface`
or `DropDownItemInterface` will
now trigger a `\TypeError` if these return types are missing.

### PositionInterface enforced {#positioninterface-enforced}

The `\TYPO3\CMS\Backend\Template\Components\PositionInterface` now enforces
strict type hints:

-   `getPosition(): string`
-   `getGroup(): int`

This interface allows buttons to define their own fixed position and group,
which automatically override the position and group parameters passed to
`ButtonBar::addButton()`.

### Icon nullability {#icon-nullability}

Icons are now consistently nullable across all button types. The
`AbstractButton::$icon` property and related getter/setter methods now use
`?Icon` instead of `Icon`.

This affects classes extending
`AbstractButton`, including
`LinkButton`,
`InputButton`, and
`SplitButton`.

> [!NOTE]
> While icons are technically optional at the type level, validation methods
> may still require icons for buttons to be considered valid.

### Method signature changes {#method-signature-changes}

Several methods now have stricter parameter types or modified signatures:

-   `MenuItem::isValid()` and `Menu::isValid()` no longer accept
    parameters
-   `AbstractDropDownItem::render()` now declares a `string` return
    type
-   Various setter methods now require strict type hints for their parameters

### Return type consistency {#return-type-consistency}

Abstract classes now use `static` return types for better inheritance
support, while concrete implementations may use `self` or `static`
depending on extensibility requirements.

### SplitButton API improvement {#splitbutton-api-improvement}

The `SplitButton::getButton()` method has been replaced with
`getItems()`, which returns a type-safe
`SplitButtonItems` DTO
instead of an untyped array.

**Old (removed):**

```php
public function getButton(): array  // Returns array with magic keys 'primary' and 'options'
```

**New:**

```php
public function getItems(): SplitButtonItems  // Returns typed DTO
```

The `SplitButtonItems` DTO provides:

-   `public readonly AbstractButton $primary` \- The primary action button
-   `public readonly array $options` \- Array of option buttons

This change improves type safety and prevents runtime errors from accessing
non-existent array keys.

## Affected installations {#affected-installations}

All TYPO3 instances with custom backend components, such as buttons, menus, or
dropdown items, that extend or implement the affected interfaces are impacted.

## Migration {#migration}

Extension authors should:

1.  **Verify custom button implementations** have correct return types on
    interface methods.
1.  **Check custom classes extending abstract buttons** use proper strict types.
1.  **Update \`isValid()\` calls** on `MenuItem` and `Menu` objects
    (remove the parameter).
1.  **Handle nullable icons** when working with `getIcon()` methods.

### Example: implementing ButtonInterface {#example-implementing-buttoninterface}

```php
use TYPO3\CMS\Backend\Template\Components\ButtonInterface;

// Before
class CustomButton implements ButtonInterface {
    public function isValid() { ... }
    public function render() { ... }
    public function getType() { ... }
}
```

```php
use TYPO3\CMS\Backend\Template\Components\ButtonInterface;

// After
class CustomButton implements ButtonInterface {
    public function isValid(): bool { ... }
    public function render(): string { ... }
    public function getType(): string { return static::class; }
}
```

### Example: working with MenuItem/Menu {#example-working-with-menuitem-menu}

```php
// Before
if ($menuItem->isValid($menuItem)) { ... }
```

```php
// After
if ($menuItem->isValid()) { ... }
```

### Example: nullable icons {#example-nullable-icons}

```php
// Handle nullable icon return
$icon = $button->getIcon();  // Now returns ?Icon
$html = $icon?->render() ?? '';
```

### Example: using SplitButton with typed DTO {#example-using-splitbutton-with-typed-dto}

If you were directly accessing the `getButton()` method:

```php
// Before
$items = $splitButton->getButton();
$primary = $items['primary'];  // Magic string key
$options = $items['options'];  // Magic string key
```

```php
// After
$items = $splitButton->getItems();
$primary = $items->primary;  // Type-safe property access
$options = $items->options;  // Type-safe property access
```
