Vue Basis: How to Create Reusable Input Component
WebCraft Notes
Posted on January 9, 2024
Check this post in my web notes
In real-world commercial projects, it's common to encounter designs featuring identical styled components and functionalities. Writing extensive lines of code for each instance can be tedious, and the quest for an efficient solution becomes paramount. Enter the concept of reusable components—a boon for developers seeking both flexibility and functionality in their codebase. In this post, we'll embark on a journey to create a versatile and reusable input component for our Vue.js project. Discover how to streamline your code and enhance project efficiency by implementing a single, adaptable input solution wherever it's needed! So let's do it:
I will create a new project for testing purposes by using the instructions from my previous post. If you do not have a project you can do the same. After we create a project and remove unneeded components, we can add some styles and dive into coding.
Setting Up the Project
So we will create a "MainInput.vue" component where we will add one input and borrow styles from UI Verse.
<template>
<input class="input" placeholder="text">
</template>
<script>
export default {
name: 'MainInput',
}
</script>
Then in our "App.vue" file, we will import "MainInput.vue" component and also add some styles like gradient and glassmorphism for better UI.
<template>
<main>
<div class="container">
<h1>Vue Input Component</h1>
<div class="input-wrapper">
<MainInput />
</div>
</div>
</main>
</template>
<script>
import MainInput from './components/MainInput.vue';
export default {
name: 'App',
components: {
MainInput
}
}
</script>
Okay, now our project and input are ready for the next steps.
We have an input that could be imported wherever we want, so it's already reusable. But not really! We need to implement a possibility to work with data and update some styles dynamically.
Implementing Data Binding
First, data. We need our component to receive data from the user and send that data to the parent component, also that would be great if our input component could receive data from the app (if we would like to update data from the database for example) and react to users' updates. We will not use "v-model" directive but will directly bind our input "value" attribute and we will add "v-on:input" listener to react to user updates that will be sending data directly to the parent component. Also, we need to receive data from the parent app, so we will add an "inputValue" as props. Here how it will look like:
<template>
<input class="input"
placeholder="text"
type="text"
:value="inputValue"
v-on:input="$emit('update:inputValue', $event.target.value)">
</template>
<script>
export default {
name: 'MainInput',
props: {
inputValue: {
type: String,
required: false
}
}
}
</script>
In the parent app, we will send data as props and listen for events from the child component. Here is how it will be changed:
<template>
<main>
<div class="container">
<h1>Vue Input Component</h1>
<div class="input-wrapper">
<MainInput
:inputValue="inputValue"
@update:inputValue="inputValue = $event"/>
</div>
</div>
</main>
</template>
<script>
import MainInput from './components/MainInput.vue';
export default {
name: 'App',
components: {
MainInput
},
data() {
return {
inputValue: ''
}
}
}
</script>
Great! Now we can copy and paste our input wherever we want in a project only updating data value and it will work correctly.
Adding Flexibility with Props
Also, we might need our input to look a little bit different in different situations, for example, different colors, style (width, height), placeholder... We can achieve that with additional props with default values. Let's add those props into our input component:
<template>
<input class="input"
:placeholder="placeholder"
:type="type"
:style="`width: ${width}; border-color: ${borderColor}`"
:value="inputValue"
v-on:input="$emit('update:inputValue', $event.target.value)">
</template>
<script>
export default {
name: 'MainInput',
props: {
inputValue: {
type: String,
required: false
},
placeholder: {
type: String,
required: false,
default: 'Type here...'
},
type: {
type: String,
required: false,
default: 'text'
},
width: {
type: String,
required: false,
default: '200px'
},
borderColor: {
type: String,
required: false,
default: '#4A9DEC'
}
}
}
</script>
Posted on January 9, 2024
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.