Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Jsformvalidator Bundle Laravel Package

shopsys/jsformvalidator-bundle

A Symfony bundle from Shopsys that adds client-side JavaScript form validation by translating server-side constraints into instant browser feedback. It helps build responsive forms with consistent rules, customizable messages, and fewer validation round trips.

View on GitHub
Deep Wiki
Context7

Getting Started

shopsys/jsformvalidator-bundle is a Symfony bundle that projects your server-side validator metadata (attributes/annotations/XML/YAML on entities and form types) into the rendered form as client-side validation rules, so the browser can fail fast before a POST. For a Laravel developer, think of it as taking your FormRequest rules and emitting them as data-* hooks plus a JS validator, so you don't hand-write a parallel rule set in JavaScript. It is a fork of the original JsFormValidatorBundle maintained by Shopsys — the packaging shows 0 stars/0 dependents, but that mostly reflects it being consumed inside the Shopsys monorepo rather than a healthy standalone ecosystem.

As of v2.0.0 the fork supports Symfony 6 and 7, which removes the biggest practical objection to using it on a current project. The changelog entry is one line ("Added Symfony 6 and 7 support"), so treat the major version bump as a signal that the supported floor moved up as well — see Gotchas before upgrading an existing install.

Minimal steps (Flex-style paths; adjust for older Symfony app/config layouts):

  1. Install and let Composer resolve Symfony constraints. On Symfony 6/7 you should be able to take the v2 line directly:

    composer require shopsys/jsformvalidator-bundle:^2.0
    

    If it conflicts, check the fork's composer.json for its PHP floor and supported symfony/* ranges before pinning; on Symfony 4.4/5.x you will need the 1.7 line instead.

  2. Register the bundle in config/bundles.php. The exact class name varies by fork generation — confirm by looking under vendor/shopsys/jsformvalidator-bundle/src/:

    return [
        // ...
        Shopsys\JsFormValidatorBundle\ShopsysJsFormValidatorBundle::class => ['all' => true],
    ];
    
  3. Add the bundle config for the root key (check DependencyInjection/Configuration.php for the authoritative keys) — typically enabling attribute/annotation mapping and choosing static vs. dynamic (AJAX) constraint delivery:

    # config/packages/js_form_validator.yaml
    js_form_validator:
        enable_annotations: true
        # dynamic/delayed mode options if you don't want metadata inline in HTML
    

    On a v2/Symfony 6-7 stack, prefer PHP attributes over annotations; confirm in Configuration.php whether the annotation toggle is still honoured or now means attributes only.

  4. Make the JS available. Either install the bundle's public assets:

    php bin/console assets:install public --symlink
    

    or import the source file from vendor/.../Resources/public/js into your Encore/Webpack entry to avoid a second copy of jQuery.

  5. Wire it into your base layout, after jQuery and after the form markup:

    <script src="{{ asset('bundles/jsformvalidator/js/jsFormValidator.js') }}"></script>
    <script>
      document.addEventListener('DOMContentLoaded', function () {
        // exact initializer per README; commonly a plugin call on the form
        $('form').jsFormValidator();
      });
    </script>
    
  6. Add the bundle's form theme block if you use a custom theme, or ensure your theme preserves the data-* attributes the bundle adds; register it via twig.form_themes if needed.

First use case: a registration/contact form with NotBlank, Email, and Length on a DTO or entity. Render it, submit empty, and confirm errors appear without a network round-trip. Then view source: fields should carry validation metadata, and in dynamic mode you should see a constraint-fetch request in the network tab. If neither is true, the theme or the init call is the problem — not the constraints.

Where to look first: the bundle's Resources/public/js entry point, Resources/views/Form theme, and DependencyInjection/Configuration.php. Forks often keep the upstream README, so also diff against the original repository when something is undocumented — and on v2 diff against the v1.7 tag when a config key or asset path doesn't behave as the old docs describe.

Implementation Patterns

  • One source of truth. Define constraints on the model/DTO (and, where relevant, on the form type's constraints option) and let the bundle translate them. Don't re-implement rules in JS; the moment you do, the fork's maintenance risk becomes your maintenance burden.
  • Static vs. dynamic delivery. Inline metadata is simplest for small forms and works offline; AJAX/delayed mode keeps HTML lean for large or collection-heavy forms at the cost of an extra request and an endpoint to secure and cache. Pick per form, not per app.
  • Validation groups must line up. Set validation_groups on the form type and make sure the client side is told the same groups. Mismatched groups are the most common cause of "client passes, server rejects" or the reverse. Test each form's actual submit path, not just the default group.
  • Custom constraints need a JS counterpart. The bundle knows about core constraints; your App\Validator\StrongPassword does not unless you register a matching JS validator through the bundle's extension point (config mapping or JS registration). Until then it is silently skipped client-side while still enforced server-side — which is fine, but surprising if you expected parity.
  • Collections and prototypes. When you add a row with your own JS, re-initialize the newly inserted subtree (or re-run the initializer on the whole form). Metadata in the prototype is inert until bound.
  • AJAX/Turbo/HTMX forms. The same rule applies: re-init after any partial re-render. With Turbo, hook turbo:load (or turbo:render) rather than only DOMContentLoaded, or validation will disappear after the first navigation.
  • Progressive enhancement. Treat the client layer as UX only. Keep $form->isValid() on every submit and return proper 422/JSON errors for XHR submissions. This is the same discipline as never trusting Laravel's front-end required attributes.
  • Theming. Prefer copying the bundle's form-theme blocks into your theme over overriding the whole form_row/form_widget. A broad override will silently strip the metadata attributes and disable validation without an error.
  • Testing. Functional tests that POST invalid data never run the JS path, so keep them (they prove the server still rejects). Add a browser test (Panther/Playwright) only for the critical JS path; don't try to unit-test the projection.

Gotchas and Tips

  • v2 is a Symfony 6/7 line, not just a feature bump. The changelog names only Symfony 6 and 7 support, but a major version implies the floor moved: expect dropped Symfony 4.4/5.x, a raised PHP requirement, and possibly Twig 3-only templates and attribute-only mapping. Read composer.json and the Resources/views diff before bumping, and keep 1.7 pinned if you are still on Symfony 5.
  • Upgrading from 1.7 to 2.0. Diff the release range (v1.7.0...v2.0.0) for renamed config keys, changed DI service ids, moved asset paths, and changes to the data-* attribute names or the initializer signature. Re-verify each form's rendered HTML after the bump: a silent theme or attribute rename disables validation with no error, and your existing JS init call may now be a no-op.
  • Still treat it as a vendored internal dependency. Zero dependents on the package page does not mean zero usage, but it does mean you are effectively on your own for upgrades. Pin the version, read the fork's changelog/diff before bumping, and be prepared to patch a fork. The v2 release reduces the Symfony-lag risk considerably, but it does not create a community around the package.
  • The fork exists because upstream stalled. v2 is fork-only: upstream still has no Symfony 6/7 support. When debugging, search issues/PRs in both the Shopsys fork and the original repository; a fix may exist upstream that was never merged here — but do not assume upstream docs describe the v2 behaviour.
  • Assets and jQuery. assets:install is required for the bundles/... asset path. If you bundle through Encore, import from vendor/.../Resources/public/js and do not let the bundle ship a second jQuery — duplicate jQuery silently breaks plugins rather than throwing. Re-check the built asset path after the major bump; it may have moved under a new directory name.
  • Script order matters. jQuery → bundle JS → initializer. If init runs before the library loads, nothing happens and there is often no console error.
  • Custom themes silently drop metadata. Before debugging JS, inspect the rendered HTML and confirm the field has the bundle's data-* attributes. If they're missing, the problem is Twig, not validation. This is the most likely casualty of a theme that predates v2.
  • Messages are not automatically your translations. Server-side messages come from the Symfony translator (validators.en.yaml etc.); client-side messages are often hardcoded in the bundle JS or need a separate catalog. Budget time for i18n if you're not English-only.
  • Some constraints can't be projected. UniqueEntity, File, Callback, and anything DB- or request-dependent will be skipped or always pass client-side. Keep them server-side and don't advertise them as instant feedback.
  • Dynamic mode is an endpoint. It exposes your constraint graph; keep it behind the firewall if it matters, set cache headers (constraints per form class rarely change), and watch for it being hit on every keystroke if you wire it too eagerly. Check whether the URL or route name changed in v2 before deploying behind a strict CSP/route allow-list.
  • Large forms bloat. Inline metadata on a 100-field form can noticeably increase HTML size and paint time; switch that form to dynamic mode or split it.
  • Hidden fields (_token, IDs) are typically ignored. Don't expect CSRF or identifier fields to have client rules; that's normal.
  • Environment behavior. Consider disabling client validation in test for deterministic assertions, or keep it enabled in dev to catch projection regressions early — pick one deliberately.
  • Debugging checklist: (1) is the JS loaded exactly once? (2) do fields carry metadata in the DOM? (3) did init run after render? (4) any console errors? (5) in dynamic mode, did the constraint request return 200 with the expected JSON? (6) for custom constraints, does the JS validator know the constraint name? (7) after a v1→v2 upgrade, does the bundle config key still match Configuration.php?
  • Three extension points cover most needs: the DI configuration, the form theme blocks, and custom JS validator registration. For anything deeper, use a compiler pass or service override rather than editing vendor/.
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
elsayed85/laravel-api-exceptions
ouhssini/laravel-demo-mode
daworks/ncloud-outbound-mailer-driver
gp247/cms
ignibyte/aic-gates
nexa-merchant/blog
novasa/laravel-language-center
opencage/geocode
adolfoholzer/parameters
livenetworks/ln-starter
shitoudev/permissionmanager
johannesclimacus/laravel-tui
hocvt/seotools
vitalybaev/sypexgeo
amphibee/themosis-ignition
gito-me/fast-excel
frankyso/laravel-ipaymu
geolize-studio/laravel-chile
boomerangui/chat
cgv/localized-resource