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
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
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
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
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
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
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).