Symfony 8.1 brings many improvements to the Form component, including new features for multi-step forms and quality-of-life options for some form types.

Form Flows Improvements

Silas Joisten Julien Robic Romain Monteil
Contributed by Silas Joisten , Julien Robic and Romain Monteil in #62566 , #62578 and #63335

Form flows (multi-step "wizard" forms) landed in Symfony 7.4, and Symfony 8.1 improves the feature with three additions that make flows easier to build and render.

First, the NavigatorFlowType now supports a with_reset option that adds a button to restart the entire flow:

1
2
3
$builder->add('navigator', NavigatorFlowType::class, [
    'with_reset' => true,
]);

Second, the new createFormFlowBuilder() shortcut in the base controller lets you define flows inline, just like createFormBuilder() does for regular forms:

1
2
3
4
$flow = $this->createFormFlowBuilder(new User())
    ->addStep('personal', PersonalType::class)
    ->addStep('account', AccountType::class)
    ->getForm();

Finally, we added new form_flow_* Twig functions to render flow navigation and progress information without accessing internal form variables:

1
2
3
4
5
6
7
8
<p>
    Step {{ form_flow_step_index(form) + 1 }}
    of {{ form_flow_total_steps(form) }}
</p>

{% if form_flow_can_move_back(form) %}
    <button name="back">Back</button>
{% endif %}

A daisyUI Form Theme

Loïc Ovigne
Contributed by Loïc Ovigne in #60334

Symfony already ships form themes for Bootstrap and Foundation. Symfony 8.1 adds a new theme for daisyUI, a popular component library built on top of Tailwind CSS. Enable it the same way as any other theme:

1
2
3
# config/packages/twig.yaml
twig:
    form_themes: ['daisyui_5_layout.html.twig']

Your text inputs, selects, checkboxes, radios, range sliders, file inputs, and error messages are now rendered with daisyUI's classes and markup out of the box.

Customizing DateType Sub-Field Labels

Guillaume Van Der Putten
Contributed by Guillaume Van Der Putten in #63631

When DateType is rendered with the choice or text widget, it splits into three sub-fields whose labels were always the generic "Year", "Month", and "Day". Symfony 8.1 adds a labels option (just like DateIntervalType already had) so you can customize them:

1
2
3
4
5
6
7
8
$builder->add('publishedAt', DateType::class, [
    'widget' => 'choice',
    'labels' => [
        'year' => 'Publication year',
        'month' => 'Publication month',
        'day' => 'Publication day',
    ],
]);

The option accepts partial arrays, so you can override only some labels.

Smarter BirthdayType single_text Widget

Nicolas Grekas
Contributed by Nicolas Grekas in #58871

When you render BirthdayType with the single_text widget, the browser displays a native <input type="date">. Until now, that input let users pick any date, even years outside the range allowed by the field.

In Symfony 8.1, BirthdayType automatically sets the min and max HTML attributes based on its years option, so the native date picker is constrained to the valid range:

1
2
3
4
$builder->add('birthday', BirthdayType::class, [
    'widget' => 'single_text',
]);
// renders <input type="date" min="..." max="..."> automatically

If you set attr.min or attr.max yourself, your values are respected.

Submitting Forms with Unchecked Checkboxes

Filip Likavčan
Contributed by Filip Likavčan in #45081

Browsers don't send unchecked checkboxes in form submissions. This caused a long-standing problem: a checkbox bound to a property that defaults to true stayed true after submitting the form unchecked, because the field looked "missing" rather than "false".

Symfony 8.1 fixes this in the request handlers: when a submitted form contains a checkbox that's absent from the request, Symfony now submits it as its false value, so the bound data is correctly set to false. This happens automatically and requires no configuration. PATCH requests are excluded on purpose, since partial updates must leave omitted fields untouched.

Choosing the UID Format in EntityType

Louis-Arnaud
Contributed by Louis-Arnaud in #63371

When an entity is identified by a UID (a Uuid or Ulid from the Uid component), EntityType renders that identifier as the value of each choice. Symfony 8.1 adds a uid_format option to control how the identifier is serialized: 'base32', 'base58', 'binary', 'hex', or 'rfc4122'.

1
2
3
4
5
6
use Symfony\Bridge\Doctrine\Form\Type\EntityType;

$builder->add('category', EntityType::class, [
    'class' => Category::class,
    'uid_format' => 'base58', // shorter, URL-friendly choice values
]);

The option defaults to null, which keeps the previous behavior (Base32 for ULIDs and RFC 4122 for UUIDs).

Published in #Living on the edge