In this article we will be building an input component using Vue and Tailwindcss.
It consists of 3 sections -
Getting Started
Have a look at the component how it will look like. I have added different options for adding label
, icons
, error messages
etc. to the component.
The Input Component
Create a file called TextInput.vue
in /src/Shared/TextInput.vue
and add
// TextInput.vue <template> <div> <label v-if="label" class="form-label block mb-1 font-semibold text-gray-700" :for="id" >{{ label }}</label > <div class="relative"> <input :id="id" ref="input" v-bind="$attrs" class="px-2 py-2 h-12 leading-normal block w-full text-gray-800 bg-white font-sans rounded-lg text-left appearance-none outline-none" :class="[ { 'border-red-400': errors.length, 'pl-12': withIcon === true }, classes ]" :type="type" :value="value" @input="$emit('input', $event.target.value)" @keydown="$emit('keydown', $event)" @blur="$emit('blur', $event)" @keyup="$emit('keyup', $event)" /> <div v-if="errors.length" class="text-red-600 mt-1 text-sm"> {{ errors[0] }} </div> <svg class="absolute text-red-600 fill-current" style="top: 12px; right: 12px" v-if="errors.length" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" > <path d="M11.953,2C6.465,2,2,6.486,2,12s4.486,10,10,10s10-4.486,10-10S17.493,2,11.953,2z M13,17h-2v-2h2V17z M13,13h-2V7h2V13z" /> </svg> <div class="absolute left-0 top-0 bottom-0 w-10 block ml-2" v-if="withIcon" > <slot name="icon"></slot> </div> </div> </div> </template> <script> export default { name: 'TextInput', inheritAttrs: false, props: { id: { type: String, default() { return `text-input-${this._uid}`; } }, type: { type: String, default: "text" }, value: String, label: String, errors: { type: Array, default: () => [] }, withIcon: { type: Boolean, default: false }, bordered: { type: Boolean, default: true } }, methods: { focus() { this.$refs.input.focus(); }, select() { this.$refs.input.select(); }, setSelectionRange(start, end) { this.$refs.input.setSelectionRange(start, end); } }, computed: { classes() { return { "border-2 focus:border-blue-600 focus:border-blue-600": this.bordered === true, "border bg-gray-200 focus:bg-white": this.bordered === false }; } } }; </script>
Using the component
Create a file called ExampleComponent.vue
in /src/components/ExampleComponent.vue
and add
<!-- ExampleComponent.vue --> <template> <div class="max-w-lg mx-auto my-12"> <!-- examples with lables --> <div class="border-l-4 border-blue-500 p-3 rounded mb-6 shadow bg-gray-100 font-semibold text-gray-600 tracking-wide text-lg" > Input components with labels </div> <text-input label="Email" class="mb-4"></text-input> <text-input label="Password" type="password" class="mb-4"></text-input> <!-- examples with label ended --> <!-- examples with icons --> <div class="border-l-4 border-blue-500 p-3 rounded my-10 mb-6 shadow bg-gray-100 font-semibold text-gray-600 tracking-wide text-lg" > Input components with Icons </div> <text-input class="mb-4" with-icon placeholder="Enter your email..."> <template #icon> <svg class="mt-2 w-8 h-8 stroke-current text-gray-100" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg" stroke="currentColor" > <path d="M3 8L10.8906 13.2604C11.5624 13.7083 12.4376 13.7083 13.1094 13.2604L21 8M5 19H19C20.1046 19 21 18.1046 21 17V7C21 5.89543 20.1046 5 19 5H5C3.89543 5 3 5.89543 3 7V17C3 18.1046 3.89543 19 5 19Z" stroke="#4A5568" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" /> </svg> </template> </text-input> <text-input class="mb-4" type="password" with-icon placeholder="Enter your password..." > <template #icon> <svg class="mt-2 w-8 h-8 stroke-current text-gray-100" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg" stroke="currentColor" > <path d="M12 15V17M6 21H18C19.1046 21 20 20.1046 20 19V13C20 11.8954 19.1046 11 18 11H6C4.89543 11 4 11.8954 4 13V19C4 20.1046 4.89543 21 6 21ZM16 11V7C16 4.79086 14.2091 3 12 3C9.79086 3 8 4.79086 8 7V11H16Z" stroke="#4A5568" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" /> </svg> </template> </text-input> <!-- examples with icons ended --> <!-- examples with error messages --> <div class="border-l-4 border-red-500 p-3 rounded mb-6 mt-10 shadow bg-gray-100 font-semibold text-gray-600 tracking-wide text-lg" > Input components with Error Messages </div> <text-input label="Email" class="mb-4" :errors="errors['errorEmail']" @keydown="delete errors['errorEmail']" > </text-input> <text-input label="Password" type="password" class="mb-4" :errors="errors['errorPassword']" @keydown="delete errors['errorPassword']" ></text-input> <!-- examples with error messages ended --> </div> </template> <script> import TextInput from "@/Shared/TextInput"; export default { components: { TextInput }, data() { return { errorEmail: "", errors: { errorEmail: ["The email field is required."], errorPassword: ["The password confirmation does not match."] } }; } }; </script>
Props
default option
Name | Type | Description | Accepted |
---|---|---|---|
type | String | Input types | text , default html5 input types |
label | String | Label of the input | |
withIcon | Boolean | if set, icon is shown | true, false |
errors | Array | Error that need to be shown with the input | |
bordered | Boolean | input has border or not | true , false |
Happy Coding :)
Top comments (1)
thanks, that was a good guid for me to make form components