DEMO / LiveComponent

Auto-Validating Form

Enter a bad email or leave the password empty, and see how the form validates in real time!
This renders a normal Symfony form but with extras added on top, all generated from Symfony & Twig.

// ... use statements hidden - click to show
use App\Form\RegistrationFormType;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\Form\FormInterface;
use Symfony\UX\LiveComponent\Attribute\AsLiveComponent;
use Symfony\UX\LiveComponent\Attribute\LiveAction;
use Symfony\UX\LiveComponent\Attribute\LiveProp;
use Symfony\UX\LiveComponent\ComponentWithFormTrait;
use Symfony\UX\LiveComponent\DefaultActionTrait;

#[AsLiveComponent]
class RegistrationForm extends AbstractController
{
    use ComponentWithFormTrait;
    use DefaultActionTrait;
    #[LiveProp]
    public bool $isSuccessful = false;

    #[LiveProp]
    public ?string $newUserEmail = null;

    protected function instantiateForm(): FormInterface
    {
        return $this->createForm(RegistrationFormType::class);
    }

    public function hasValidationErrors(): bool
    {
        return $this->getForm()->isSubmitted() && !$this->getForm()->isValid();
    }

    #[LiveAction]
    public function saveRegistration()
    {
        $this->submitForm();

        // save to the database
        // or, instead of creating a LiveAction, allow the form to submit
        // to a normal controller: that's even better.
        // $newUser = $this->getFormInstance()->getData();

        $this->newUserEmail = $this->getForm()
            ->get('email')
            ->getData();
        $this->isSuccessful = true;
    }
}
<div
    {{ attributes }}
>
    {% if isSuccessful %}
        <div>Welcome {{ newUserEmail }}!</div>
    {% else %}
        {{ form_start(form, {
            attr: {
                'novalidate': true,
                'data-action': 'live#action:prevent',
                'data-live-action-param': 'saveRegistration',
            }
        }) }}
            {{ form_row(form.email) }}
            {{ form_row(form.password) }}
            {{ form_row(form.terms) }}

            <button
                type="submit"
                class="btn btn-primary {{ this.hasValidationErrors ? 'disabled' : '' }}"
            >Register</button>

            {{ form_rest(form) }}
        </form>
    {% endif %}
</div>