Ipl-html: Introducing new Form Element Decorators

by | Nov 25, 2025

A Fresh Take on Form Element Decorators

Decorators have always been a powerful concept in Icinga Web’s form system — letting developers control how form elements are displayed without hardcoding markup everywhere. But until recently, the decorator system had its limits. The new implementation of form element decorators completely reimagines this approach, offering cleaner logic and better flexibility.

In this article, we’ll explore what’s new, why it’s better, and how to use it effectively in your own forms.

What Are Form Element Decorators?

In simple terms, decorators define how each form element is rendered. They act like small, reusable wrappers that can add labels, descriptions, containers, or error messages around inputs — all without touching the element’s core behavior. You can mix and match them to define exactly how your fields should look in HTML.

Why a New Implementation?

The legacy decorator system had a few well-known issues:

  • Early decoration: Elements were decorated as soon as they were added to the form. This meant the decorated structure was baked in too early, often leading to unpredictable rendering behavior later on.

  • Implicit wrappers: Because decorators wrapped elements automatically, it became common to assume that every element always had a wrapper, even though that wasn’t guaranteed.

  • Tight coupling: The old decorators were actual BaseHtmlElement instances. This made them harder to manage and often caused decoration to happen only during rendering, leading to timing issues when inspecting or adjusting elements dynamically.

The new system — based on ipl\Html\Contract\FormElementDecoration — fixes all of these pain points by introducing a cleaner, more predictable rendering process.

What’s Better About the New Decorators

  • Render-Time Decoration: Decoration now happens only when the form is rendered. This ensures that elements remain untouched until they actually need to be displayed. You can modify, inspect, or replace elements freely before rendering — without triggering unwanted markup changes.
  • Predictable, Isolated Behavior: Each decorator is identified by a unique name, which makes it easy to replace or remove individual decorators without breaking others. The isolation between decorators prevents conflicts and avoids side effects when modifying the rendering chain.
  • Greater Accessibility by Default: The built-in decorators automatically handle key accessibility features, such as linking labels and descriptions properly.
  • Fine-Grained Control per Element: Instead of relying solely on global defaults, you can assign decorators per element. This means you can, for instance, wrap only required fields in a special container or give different styles to text fields versus checkboxes — without redefining everything.

How to Use the New Decorators

Setting Default Decorators

You define how your form elements should be decorated by setting default decorators:

$form = (new Form())
    ->setDefaultElementDecorators(['
        Label',         // render element label
       'RenderElement', // render the element
       'Description'    // render element description
    ]);

 

This means every element in your form will automatically render its label, followed by the element itself and then its description. Simple and predictable.

Overriding Per Element

Need a different layout for one element? You can override its decorators easily:

$form->addElement('password', 'user_password', [ 
    'label' => 'Password',
    'description' => 'Must be at least 8 characters long',
    'decorators' => [
        'custom-label' => [
            'name' => 'Label',
            'options' => ['class' => ['custom-label', 'text-bold']], // add different css classes only for this label
        ],
        'RenderElement',
        'Description'
    ]
]);

 

Only this specific element uses the custom decorator list, while others still follow the global defaults.

Adding Wrappers and Custom Tags

You can also wrap groups of elements or individual ones in custom HTML tags. For example:

$form->setDefaultElementDecorators([
    'Label',
    'RenderElement',
    'Description',
    'wrapper' => [
        'name' => 'HtmlTag',
        'options' => ['tag' => 'div', 'class' => 'form-field-wrapper']
    ] 
]);

 

This will produce markup where each label, input, and description are enclosed in a <div class="form-field-wrapper"> container — great for structured layouts or CSS styling.

You can even apply wrappers conditionally (e.g., only around required fields) or append/prepend additional tags using transformations like Wrap, Append, or Prepend.

Built-In Decorators

The new system includes a set of ready-to-use decorators out of the box:

  • Label – Adds a <label> linked to your input.

  • RenderElement – Inserts the form element itself.

  • Description – Adds a short explanatory paragraph or help text.

  • HtmlTag – Wraps, prepends, or appends custom tags around decorated output.

  • Fieldset – Handles legend and description for grouped elements.

  • Errors – Displays validation errors in a consistent way.

Registering Custom Decorators

You can even define and register your own decorators to extend functionality. Simply tell the form where to find them:

$form->addElementDecoratorLoaderPaths([
    ['My\App\FormDecoration', 'Decorator']
]);

 

Now you can use your own decorator classes by their short names — a clean and modular approach that keeps your codebase maintainable.

Enabling the New Decorators in your existing custom Form classes extending CompatForm

If your form class extends ipl-web/CompatForm, you can easily switch to the new decorators without major changes. Just make sure to call CompatForm::applyDefaultElementDecorators() before adding any elements to the form. This ensures that all elements use the updated decorators right from the start.

For more details and examples, check the documentation at ipl-html.

Want to dive deeper? Visit the documentation for more details and examples: https://github.com/Icinga/ipl-html/blob/main/doc/45-Form-Decorators.md

You can also discover more exciting ipl-html features in this blog post: https://icinga.com/blog/ipl-how-to-use-ipl-html/

You May Also Like…

 

Using Icinga 2 on NixOS

Using Icinga 2 on NixOS

I use NixOS by the way. And today I'm going to show you how to operate a simple Icinga setup using that operating...

Subscribe to our Newsletter

A monthly digest of the latest Icinga news, releases, articles and community topics.