Part 3(a): How to Build a Self-Contained Component
Tags: programming, vue, frontend, webdev
Published: 2023-06-02 00:17:24

**What are self-contained components?**

When building frontend applications, it's more advised to approach development with the mindset of breaking app components into small, independent, and reusable bits. This will help manage the codebase by knowing where to go when things go wrong.

In frontend development, a self-contained component refers to a modular unit of code that encapsulates both the visual elements (HTML or JSX), styles (CSS), and behavior (JavaScript) required to render a specific part of a user interface. These components are designed to be independent and reusable, making them a fundamental building block for creating complex user interfaces. This component allows configuration and accepts data as props.

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/1hnwkqgl0bhiprb0e6uh.png)

From the diagram above, there are a few things to take note of:

- Input: There are two data input fields; data is passed as a prop to the component in the first input, while the second is user-input data.


- Components: It's independent, modular, and reusable. accept data through props and pass it to the internal configurations for processing.


- Internal Configuration: Components can often accept props or configuration options to customize their appearance or behavior. This flexibility allows them to adapt to different use cases without modifying their underlying code; all the work has been done within the component.

In this example, we will be using VueJs to create a reusable input field, a dropdown select, and a modal popup component. These components are what we will use moving forward in developing the project phase of this series. This component is not an accessible input since it lacks some important accessibility features such as keyboard control and wai-aria roles.

This is created for the sake of explaining this concept to readers in a short and concise way. However, one should strive to make one's app accessible when building for production.

**Building a re-usable form input**

To build a self-contained component in Vue, you can follow these steps:

Note: We are using the existing Vue project set up from Part 1.

Step 1: Create a new folder, e.g., name it common. in your component directory.
This folder will contain all our reusable components 

Step 2: Create a new component file.
Inside your project directory, navigate to the src/components/common folder (or create it if it doesn't exist). Create a new file for your component, e.g., CustomInput.vue.

Step 3: Define the components
Open the CustomInput.vue file in your preferred code editor and define your component using Vue's Single File Component syntax. 

src/components/common/CustomInput.vue
```Javascript
<template>
   <div class="form-control">
      <label v-show="isLabel" :for="IdName">{{ labelValue }}</label>
      <input 
         :type="CustomType"
         class="custom__inputs"
         :placeholder="PlaceHolder"
         :value="value"
         :readonly="readOnly"
         :id="IdName"
         :autofocus="setFocus"
         :autocomplete="setAutocomplete"
         @input="onInput"
      >
      <p v-show="withValidation">{{ errorMsg }}</p>
   </div>
</template>
<script>
export default {
   name:'CustomInput',
   props: {
      labelValue: {
         type: String,
         default: 'Label',
      },
      isLabel: {
         type: Boolean,
         default: false,
      },
      CustomType: {
         type: String,
         default: 'text'
      },
      PlaceHolder: {
         type: String,
         default:'',
      },
      value: {
         type: String,
      },
      readOnly: {
         type: Boolean,
         default: false,
      },
      IdName: {
         type: String,
         default: '',
      },
      setFocus: {
         type: Boolean,
         default: false,
      },
      setAutocomplete: {
         type: Boolean,
         default: true,
      },
      withValidation: {
         type: Boolean,
         default: false,
      },
      errorMsg: {
         type: String,
         default: ''
      }
   },
   methods: {
      onInput(e){
         this.$emit('input', e.target.value);
      }
   }
}
</script>
<style lang="scss" scoped>
   //component styles
   .form-control {
      display: flex;
      flex-direction: column;
      align-items: flex-start;
      margin-bottom: 2rem;

      & label {
         padding: 5px 2px;
      }

      & p {
         margin: 2px 0px;
         font-size: 14px;
         color: #e74e3c;
      }
   }

   .custom__inputs {
      padding: 10px ;
      font-size: 16px;
      border: 2px solid #eee;
      border-radius: 5px;
      width: 100%;

      &:focus {
         border: 3px solid #67679ac5;
      }
   }
</style>
```

Step 4: Use the component.
To use your custom input component, you can import it into another Vue component and include it in the template. For example, go to the view folder in the same src folder and use the component in Home.vue as follows:

```Javascript
<template>
  <div class="home">
    <!-- render emit data -->
    <form class="form__container" action="">
      <CustomInputVue
        v-model="firstName"
        :value="firstName"
        :PlaceHolder="'Firstname'"
        :withValidation="true"
        :errorMsg="'required'"
        :isLabel="true"
        :labelValue="'FirstName'"
      />
      <CustomInputVue
        v-model="email"
        :value="email"
        :PlaceHolder="'hello@example'"
        :withValidation="true"
        :errorMsg="'required'"
        :isLabel="true"
        :labelValue="'Email'"
      />
      <button class="btn">submit</button>
    </form>

  </div>
</template>

<script>
// @ is an alias to /src
import CustomInputVue from '@/components/common/CustomInput.vue'


export default {
  name: 'HomeView',
  components: {
    CustomInputVue,
  },
  data(){
    return {
      parentData: 'You are learning about props in this article',
      newMsg: 'hello',
      firstName: '',
      email: ''
    }
  },
}
</script>

<style lang="scss" scoped>
  .form__container {
    width: 40%;
    margin: 0 auto;
  }

  .btn {
    background: #0000ff;
    color: #fff;
    font-size: 18px;
    padding: 7px 15px;
    border: none;
    border-radius: 5px;

  }
</style>

```
There are a few things to note about the usage of this component 

`labelValue`: It accepts string data; it's used for passing the label title for an input. Should be used with isLabel when set to true.  
   
`isLabel`: It accepts boolean data; it's false by default; set it to true if you want to use the internal label; otherwise, it should be false.  

`CustomType`: It accepts string data;  you can pass the input type you need to work with to it.

`PlaceHolder`: It accepts string data.
        
`value`: It accepts string data;

`readOnly`: It accepts boolean data;  should be set to true if you need your form input to be read-only.
    
`IdName`: This is for passing an id to the form input, it accepts a string of data.
 
`setFocus`: Accepting a boolean value, this is for controlling the input field focus.

`setAutocomplete`: This is for setting the HTML autocomplete on text input.
       
`withValidation`: This is false by default, but if you want to add a validation message to the props, you can set it to true.

`errorMsg`: Accepting a string of data; as an error message should be used with "with validation" set to true.

An image of the final result:
![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/opgnjnrebkkv2u3uaf6y.png)

**How to build a custom dropdown select Part 3(a)**