Authoring Validatable Vue Input Components
Tips on creating versatile custom inputs with VeeValidate
Building Vue.js components is very fun and straightforward, you can build almost anything and it will work most of the time. But when it comes to components that serve as inputs there are few things to cover.
We will start with covering the basics using Vue.js guide then build our way up to integrate the component to work seamlessly with vee-validate.
Implement the v-model interface
As mentioned in the official Vue guide, your component should be able to work with the v-model
directive, which boils down to emitting an input
event whenever the value changes and it should accept a value
input, which of course can be customized to cover other events and props.
As a start, our custom text component would look like this:
It doesn’t do much yet, it just accepts a value prop and emits an event whenever the user manipulates the input via the native input
event, so in a way, it translates the interaction from native HTML input to a Vue component.
This way, using v-model
is the only way this component mutates the state, which is simple and manageable. And above all else is re-usable.
Add events as needed
Native HTML inputs have a plethora of events that you can listen to, but most of the time you are only interested in a few of them, in our case we have been only interested in the input
event, we should add some useful events as well, like focus
, blur
, and change
.
This might not be necessary when working with your own components in your own projects but if you are planning to publish your components to masses then you might need to cover a few events that the users might be interested in listing to, for example, blur could be used to trigger UI change or trigger validation on that input.
Add props
Like events, some users may be interested in setting some props on your component like they would on a native HTML input, for example, the disabled
attribute is extremely valuable, maybe a label
and name
props as well.
Also having the input type always set to text
isn’t very accessible on mobile devices since the keyboards can be context-aware to display relevant characters to the input type, like @
for emails and .com
for URLs.
Let us add our props and bind it to the inner input attributes:
We can go a long way with this, for example: autocomplete
, placeholder
and plenty more.
Enable Validation
Most likely you want to validate this little component of ours, we have two approaches:
- Validate it from the parent as a response to the input event (reactive).
- Have it validate itself whenever the value changes (passive).
Now while the second option makes it sound more contained and useful, you should realize that it forces validation on the component, It is opt-out instead of opt-in.
Furthermore in the lines of the single responsibility pattern: Should the component be concerned if its value is valid? or is it the concern of the consumer of said value, the consumer being the parent component or the form component.
The first approach simplifies our component implementation and makes it lighter, the component should only report its value, not its validness.
Vee-validate supports both approaches, but depending on your implementation, the second approach could be more difficult to maintain since it requires communicating the errors to the parent component to prevent form submission for example until everything is valid.
For now, let us go with the first approach, we don’t have to add anything to our component, it will just work:
Here comes the issue, our parent component can tell if the component is valid or not using the validator API, but not our user. Going back to our question if the component should be concerned if its value is valid or not, maybe it should since we need to display some red flags to the user as well.
But instead of it saying “my value is valid” maybe it should instead ask: “is my value valid?” which can be done using props easily.
Let us add error
prop to our component and bind it to its view:
Well, now we got a clean component that can be validated with a few nice features. The only thing remaining is to fix some issue with vee-validate.
Vee-validate validates components the same way it validates HTML inputs, mainly using events but what happens when you call validateAll
to validate manually before form submission. vee-validate doesn’t know the current value of the input since it doesn’t track them, also what if you want to validate on blur instead? Our component does not emit the value with the blur event, so the validator wouldn’t know what to do.
VeeValidate Component Options
There is a newly added feature called component options, which is a contract between the component and VeeValidate. It allows your component to tell vee-validate
some stuff, like how to fetch the current value, the component name and which events should be used to validate the component.
And that is it, we got ourselves a nice custom input component that plays well with vee-validate. Of course, there is room for improvements and there are already plenty of Vue.js component frameworks that do this very well like Vuetify.
What about other input types?
Text inputs while versatile, are lacking in many ways for some input value types. Like dates, choices, files and whatever you can think of.
I have included in the sandbox other types of inputs that you might find useful for your next component implementation. They share the same principle of what we did here: Passing values to the model and telling the validator how to fetch it.
We covered a lot here! Now go on and give your input components a nice touch. thanks for reading!