Creating <input type="button"> the Progressive way

Using Vue 3

ยท

7 min read

Sometimes you try to do something, google it and find nothing. this is what I faced when I took FrontendMentor Challenge

Challenge image

There may blog, youtube video, or something about this, and I haven't found it. it's fine this isn't about the lack of something, but about I did something.

This blog is for beginners, I will try to describe everything as best as I can. The best way to learn is to try to implement this into your project with your style.

Quick HTML plan

In the challenge, I am required to make 5 buttons, which receive inputs from the user and display them on a different section.

Looking at it, I can make <buttons> and add onClick() event to change an innerText in <p>. but I didn't wanna write JavaScript with <form>, <input>, and <output> out there.

What is <input type="button">

Usually when I try to add <input> tags in our HTML files. I expect a user to fill out a form, whether with a password, email, or phone number. in our case, the challenge required 5 inputs that lead to different <output>.

You can check the Docs for more info

I created a simple form for now

<form>
   <input type="button" value="Mom" id="mom">
   <input type="button" value="Dad" id="dad">
   <input type="button" value="You" id="you"> 
  </form>

When I look at the form, it gives abandoned vibes. I want something cool to show, so I add some style. feel free to add your style.

/* styles.css */

:root {
  color-scheme: light dark;
  --bg-color: hsl(216 12% 8%);
  --btn-color: hsl(213 19% 18%);
  --font-color: 25 97% 53%
}

@media (prefers-color-scheme: light) {
  :root {
     --bg-color: hsl(216 12% 54%);
     --btn-color: hsl(217 12% 63%);
     --font-color: 216 12% 8%;
  }
}


*,
*::before,
*::after {
  box-sizing: border-box;
}

body {
  height: 100vh;
  display: grid;
  place-items: center;
  background-color: var(--bg-color);
  color: hsl(var(--font-color) / .9)
}

.grid {
  display: grid;
  gap: 1.5rem;
}


.flex {
  display: flex;
  gap: 1.5rem;
}


input {
  width: 10vw;
  max-width: 500px;
  min-width: 70px;
  height: 10vw;
  max-height: 500px;
  min-height: 70px;


  border-radius: 50%;
  border: 0;
  background-color: var(--btn-color);
  color: hsl(var(--font-color) / .9);
  font-wight: 900;
  font-size: clamp(.8em, .7em + 10px, 1.5em);
}

input:hover,
input:focus {
  cursor: pointer;
}
input:active {
  transform: scale(1.05);
}

Now, that I have set our <form>. I need to catch the values of the <input> when users interact with the button.

Output Tag

When you use <from>, you are expected to provide the action attribute to receive the <input>'s values. <output> provides a way to represent those values in the DOM itself.

Check it's Docs

Let's add it to our <form>

<form oninput="greeting.value = null" id="people" class="grid">
   <input type="button" value="Mom" id="mom">
   <input type="button" value="Dad" id="dad">
   <input type="button" value="You" id="you"> 
  </form>  

<p>Hi <output form="people" name="greeting" for="mom dad you"></output> ๐Ÿ‘‹๐Ÿฝ</p>

If you thought like me. you hoped that something like this would work for '`.

<form oninput="outputName.value = inputId.Value" >
  <input id="inputId" value="Hi" type="button">
<output name="outputName" for="inputId"></output>
</form>

when you click on <input type="button"> it displays nothing. if I change the type to range it will work but not for the button, which made it obsolete.

โ€ƒ you were the chosen one.gif

If your thoughts are like mine and felt bad. This is programming you are wrong until you face an issue, fix it. then become less wrong. ๐Ÿ˜…

the Progressive way

Now that our Interactivity is gone and I need to add functionality. For this, I chose Vue.js, feel free to use whatever you want but this guide is about Vue.

progressive functionality.jpg

First, I need to install Vue. luckily, it doesn't require a building tool. I can just copy the link and I will have everything ready

<form>
...
</form>
<script src="https://unpkg.com/vue@3"></script>

If you wanna open 'unpkg.com/vue@3' in your browser, to know how is it working. Don't, there is a good documentation for Vue, check it out instead. If you wanna visit your therapist earlier read 15786 lines. If my therapist is reading this, I haven't read 15786 lines of code to write 10 lines. (โŠ™_โŠ™;)

It doesn't hurt to check if things are working.

<form id="app">
{{message}} <!-- will type: Hello Vue! -->
...
</form>

{{message}} <!-- will type: {{message}} -->

<script src="https://unpkg.com/vue@3"></script>
<script src="script.js"></script>
  // script.js

   Vue.createApp({
    data() {
      return {
        message: "Hello Vue!"
      }
    }
  }).mount('#app')

I am mounting the <form> by selecting its id in mount("#app") function. which mean the variables and the functions are accessible in our HTML file

Note: that I can mount a html tag mount("form") or even class mount(".class"), and script.js won't function outside of mounted element.

[what does mount mean in vue.js] (stackoverflow.com/questions/49137607/what-d..)

I like to start my script by selecting the element, which the user interacts with. For my case, it's <input value="">.

Vue has a way to set value of <input>, and that is v-model, which makes your life easier, they made mine easier.

For now, I focus on setting <input>'s value, if you wanna know more about v-model check the Docs.

Here is an implementation of it.

<!-- index.html -->

 <form class="grid" id="app">
    <div class="flex">
    <input type="button" v-model="greatPeople[0]">
    <input type="button" v-model="greatPeople[1]">
    <input type="button" v-model="greatPeople[2]">
    </div>
    <span>Hi <output></output> ๐Ÿ‘‹๐Ÿฝ</span>
  </form>    

  <script src="https://unpkg.com/vue@3"></script>
  <script src="script.js></script>
  // script.js

   Vue.createApp({
    data() {
      return {
        greatPeople: ["Mom", "Dad", "You"]
      }
    }
  }).mount('#app')

v-model is setting greatPeople in data() as <input>'s value. With the value in <input>in script.js, I can easily access <input v-model="">'s value in Event Handlers, which would have been harder with the old <input value="">.

Vue got our back with Event Handlers as well, I am going to focus on v-on and methods. Check its Docs.

While Vue is handling functions with methods, I can focus on creating our function.

Now that I have things set up. Let's think about functionality.

I need two function:

  • I need <input> to alter the innerText of <output>
  • I need <output> to change based on <input>'s value

to change innerText I need a variable, which changes when a function is run.

I named that variable helloPeople

// script.js

     Vue.createApp({
    data() {
      return {
        helloPeople: '',
        greatPeople: ["Mom", "Dad", "You"]
      }
    },
      methods: {
        setGreatPeople(person) {
          this.helloPeople = this.greatPeople[person]
        }
    }
  }).mount('#app')

I need <output>to show the result of the function running, in its innerText. Vue takes care of this task for us, by simply adding {{helloPeople}} to <output>.

 <form class="grid" id="app">
    <div class="flex">
    <input type="button" v-model="greatPeople[0]">
    <input type="button" v-model="greatPeople[1]">
    <input type="button" v-model="greatPeople[2]">
    </div>
    <span>Hi <output>{{helloPeople}}</output> ๐Ÿ‘‹๐Ÿฝ</span>
  </form>  

  <script src="https://unpkg.com/vue@3"></script>

I need this function to run when the user clicks <input>, this is the time for v-on to shine.

   <form class="grid" id="app">
    <div class="flex">
    <input type="button" v-model="greatPeople[0]" v-on:click="setGreatPeople(0)">
    <input type="button" v-model="greatPeople[1]" v-on:click="setGreatPeople(1)">
    <input type="button" v-model="greatPeople[2]" v-on:click="setGreatPeople(2)">
    </div>
    <span>Hi <output></output> ๐Ÿ‘‹๐Ÿฝ</span>
  </form>

while doing research I noticed that I don't know why I need to use this.function() in methods. if you like me, don't worry, I found article for us.

  Vue.createApp({
    data() {
      return {
        helloPeople: ' ',
        greatPeople: ["Mom", "Dad", "You"]
      }
    },
      methods: {
        setGreatPeople(person) {
          this.helloPeople = this.greatPeople[person]
        }
    }
  }).mount('#app')

Conclusion

With this, I have made <input type="button"> with functionality and interactivity.

Oh, by the way, I lied about describing everything. and that for a good reason.

I will try to describe everything as best as I can.

If you rode a bike when you were younger, you didn't need to know about friction and force to use it, although they are helpful to know why you got injured.

Same with development, you don't need to master a language or framework to develop. So if you have an idea just do it, don't be the idiot who read 15786 of code to type ten.

For me, this is the first time I use a framework successfully without a tutorial. if you are a newbie like me and get depressed think other people can do it while I can't. Don't worry, we will be able to do it as well.

Hopefully, this was helpful to you, as it was to me. If you have any questions, tips, or wanna say hi. You can reach me privately through Discord or through Twitter.

Edit: if you clicked in the Docs link, it will guide you to w3school site. Mozilla has better docs in my opinion.

kudo for Shaun Hamilton for telling me about Mozilla and more.

ย