How to Build a Real-Time Form Validator with Phoenix LiveView
Form validation is one of those tasks that every developer runs into sooner or later. Done well, it keeps bad data out and helps users…
How to Build a Real-Time Form Validator with Phoenix LiveView

Form validation is one of those tasks that every developer runs into sooner or later. Done well, it keeps bad data out and helps users correct mistakes quickly. In traditional web apps, validation often happens after a full-page refresh or relies on JavaScript. With Phoenix LiveView, you can validate user input in real time as they type, entirely on the server, with almost no latency and no need for client-side code.
Start by defining a changeset in your Ecto schema. Suppose you have a schema called User, and you’re collecting an email and password. In your context module, define a function like User.changeset/2 that includes validations using Ecto’s built-in helpers such as validate_required, validate_format, and validate_length.
Next, generate a LiveView module where the form will live. In the mount/3 callback, assign a blank changeset to the socket using your schema’s changeset function. For example, you can use User.changeset(%User{}) and assign it to :changeset. This changeset will be updated continuously as the user types into the form.
In your LiveView template, use phx-change=”validate” on the form tag. This tells LiveView to send form data to the server every time an input is changed. You should also include phx-submit=”save” if the form needs to be submitted at the end.
Inside your LiveView module, define a handle_event/3 function for "validate". Inside that function, fetch the form data from the params, pass it to your changeset function again, and assign the updated changeset back to the socket. Use Ecto.Changeset.action(changeset, :validate) to make sure it runs all validations, not just ones triggered by submission.
This assign gets reflected automatically in your template. For example, you can render field-specific errors using Enum.map(changeset.errors, fn {field, {message, _}} -> … end) or use Phoenix.HTML.Form.error_tag helpers if you’re using Phoenix.HTML.FormData. Error messages will show up inline under each field without needing a page reload or manual AJAX.
To further enhance UX, add dynamic styling based on validation state. You can check if a field has errors using Ecto.Changeset.get_field/2 and apply classes like border-red-500 or text-green-700 accordingly. This gives users immediate feedback and encourages them to fix mistakes on the spot.
Real-time validation is also the perfect opportunity to handle uniqueness constraints gracefully. For example, if you want to check whether a username or email is already taken, you can query the database directly inside the validation function and add a custom error to the changeset if a duplicate is found. Be cautious with this pattern to avoid hammering the database on every keystroke. You might choose to validate on phx-blur instead of phx-change for more expensive operations like uniqueness checks.
Another neat trick is to validate passwords against strength rules. You can check for common patterns like minimum length, presence of numbers or symbols, or banned passwords. Return errors dynamically so users don’t have to wait until they submit the form to learn that their input is invalid.
Once validation passes, the user submits the form with phx-submit=”save”. In the "save" clause of your handle_event/3, repeat the changeset logic one more time, then insert the record into the database using your context module. If insertion fails, display relevant messages by merging the error changeset into your assign. If it succeeds, you can clear the form, show a flash message, or redirect.
This server-driven validation model gives you consistency, maintainability, and security. It removes the chance that client-side validation diverges from backend rules, which can lead to subtle bugs and bad data getting through. And because LiveView only sends small diffs, the performance feels almost instant, even over slower connections.
For production apps, you can extend this pattern to include debounce timing, inline tooltips, character counters, or conditional validations. You can also extract form components into reusable LiveComponents that encapsulate their own validation logic for complex forms with nested data.
Real-time validation is not just about better UX. It improves conversion rates, reduces friction, and helps users trust your app. LiveView gives you a robust and elegant way to build this behavior, fully integrated with your backend and without writing JavaScript.
If you are looking to advance your Phoenix LiveView projects, I created **Real Time Collaboration with Phoenix LiveView** to help you develop scalable, multi-user real-time apps. It emphasizes practical approaches including presence management, handling conflicts, and integrating external services for better collaboration and user experience.
메타데이터
- post_id
- e4af6607244e
- slug
- how-to-build-a-real-time-form-validator-with-phoenix-liveview-e4af6607244e
- url
- https://medium.com/@hexshift/how-to-build-a-real-time-form-validator-with-phoenix-liveview-e4af6607244e
- canonical_url
- https://medium.com/@hexshift/how-to-build-a-real-time-form-validator-with-phoenix-liveview-e4af6607244e
- author_url
- https://medium.com/@hexshift
- status
- ok
- fetched_at
- 2026-07-30 01:27:04