Table of contents
1.
Introduction
2.
What is meant by Semantics?
3.
Semantics in Vue
3.1.
Media Object component
3.2.
Forms
3.3.
Headline Component
3.4.
Buttons
3.5.
Hiding Content
3.6.
Labels
4.
FAQs
5.
Key Takeaways
Last Updated: Jul 23, 2024

Semantics in Vue

Career growth poll
Do you think IIT Guwahati certified course can help you in your career?

Introduction

While building a modern, component-based client-side application, we often forget about the foundations of web development, i.e., HTML and CSS. We write code as if the rules of writing semantic HTML are no longer relevant. As more and more people use web applications every day, the reasons we should write semantic and accessible HTML are as important today as in the past.
 

This article explores how we can build our Vue.js components to make it easier to create applications that render semantic HTML.

What is meant by Semantics?

Semantics is defined as "the study of meanings." In frontend web development, semantics refers to the code corresponding to the information on a web page instead of its presentation. It makes HTML more comprehensible by defining the different sections and layout of the web pages.

 

Modern single-page web applications are based on generic and reusable components. But often, while creating these generic, low-level building blocks of our applications, we don't know where and how these components will be used in the future. This means that we fall back to elements without semantic meaning (most divs and spans).
 

Let's now look at the various ways to build components that follow semantics in Vue.

Semantics in Vue

Let's now look at some examples of building components that follow semantics in Vue and can be easily adapted to render the appropriate HTML tag.

Media Object component

The Media Object is a relatively simple yet powerful pattern consisting of a wrapper, a body, and a figure element.
 

Code:

<template>
 <Component
   :is="tag"
   class="Media"
 >
 </Component>
</template>

<script>
export default {
 name: 'Media',
 props: {
   <!-- Pass the name of the HTML element to be rendered -->
   tag: {
     default: 'div',
     type: String
   }
 }
};
</script>
You can also try this code with Online Javascript Compiler
Run Code

 

This is the implementation of the wrapper component of the media object. The component and other UI components declare a tag property that allows us to change which HTML element is rendered. 

 

Code:

<template>
 <Media tag="figure">
   <MediaFigure
     tag="img"
     src="src/images/img"
     alt="Image"
   />
   <MediaBody tag="figcaption">
     Image
   </MediaBody>
 </Media>
</template>
You can also try this code with Online Javascript Compiler
Run Code

 

Here we have rendered the Media component as semantic <figure> and <figcaption> elements to describe an <img> element.

Forms

When creating a form, we can use elements like <label>, <form>, <textarea>, <input> and <button>.
 

Code:

<form action="/dataCollection" method="post" autocomplete="on">
 <div v-for="item in items" :key="item.id" class="formItem">
   // Labels are normally placed on top or to the left of the form fields
   <label :for="item.id">{{ item.label }}: </label>
   <input
     :type="item.type"
     :id="item.id"
     :name="item.name"
     v-model="item.value"
   />
 </div>
 <button type="submit">Submit Form</button>
</form>
You can also try this code with Online Javascript Compiler
Run Code

 

Here, we have included autocomplete='on' on the form element, and it will apply to all inputs in the form. We can also set different values for autocomplete attributes for each input field.

Headline Component

Sometimes the visual order of the headlines of an application does not correspond to their semantic order. We can have a headline component to set the visual size independently of the rendered tag in such cases.
 

Code:

<template>
 <Component
   :is="tag || `h${level}`"
   :class="`Headline Headline--${size || level}`"
 >
 </Component>
</template>

<script>
export default {
 name: 'Headline',
 props: {
   level: {
     default: '1',
     type: String
   },
   size: {
     default: null,
     type: String
   },
   tag: {
     default: null,
     type: String
   }
 }
};
</script>

<style>
.Headline {
 font-weight: bold;
}

.Headline--1 {
 font-size: 2em;
}

.Headline--2 {
 font-size: 1.75em;
}

.Headline--4 {
 font-size: 1.5em;
}
.Headline--5 {
 font-size: 1.25em;
}
.Headline--6 {
 font-size: 1em;
}
</style>
You can also try this code with Online Javascript Compiler
Run Code

 

The Headline component can be controlled using level, size, and tag. The level property decides which tag (h1-h6) has to be rendered. Using CSS classes, we have applied the style to the headings. We can also render a different HTML element by changing the tag property.
 

The headlines can be used as follows.
 

Code:

<template>
 <Headline level="1" size="2">
   h1 headline looking like h2
 </Headline>
 <Headline tag="p" size="1">
   Headline with p tag
 </Headline>
</template>
You can also try this code with Online Javascript Compiler
Run Code

Buttons

While using buttons inside a form, we must set the type. This is done to prevent submitting the form. We can also use the input to create buttons.
 

Code:

<form action="/dataCollection" method="post" autocomplete="on">
 <!-- Buttons -->
 <button type="submit">Submit</button>

 <!-- Input buttons -->
 <input type="submit" value="Submit" />
</form>
You can also try this code with Online Javascript Compiler
Run Code

 

We can also use input fields to create functional images and icons. These will act as a submit type button on forms.
 

Code:

<!-- Image -->
<form role="search">
 <label for="search" class="hidden-visually">Search: </label>
 <input type="text" name="search" id="search" v-model="search" />
 <input
   type="image"
   class="buttonImg"
   src="src/images/searchImg"
   alt="Search Image"
 />
</form>

<!-- Icon -->
<form role="search">
 <label for="searchIcon" class="hidden-visually">Search: </label>
 <input type="text" name="search" id="search" v-model="search" />
 <button type="submit">
   <i class="fas fa-search" aria-hidden="true"></i>
   <span class="hidden-visually">Search</span>
 </button>
</form>
You can also try this code with Online Javascript Compiler
Run Code

Hiding Content

Typically, it is not recommended to visually hide labels, even if the input has an accessible name. However, we can hide the visual label if the input functionality can be understood with the surrounding content.
 

Code:

<form role="search">
 <label for="search" class="hiddenVisually">Search </label>
 <input type="text" name="search" id="search" v-model="search" />
 <button type="submit">Search</button>
</form>

<!-- CSS to visually hide elements but keep them available for assistive technology -->
<style>
 .hidden-visually {
   position: absolute;
   overflow: hidden;
   white-space: nowrap;
   margin: 0;
   padding: 0;
   height: 1px;
   width: 1px;
   clip: rect(0 0 0 0);
   clip-path: inset(100%);
 }
</style>
You can also try this code with Online Javascript Compiler
Run Code

 

The search button will help the visual users identify the input field's purpose here.

Labels

Labels are used for the purpose of all form control. We must explicitly set the labels with a matching id, which is better supported by assistive technology.

 

Code:

<template>
 <form class="form">
   <div class="formItem">
     <label for="userName">Username:</label>
     <input type="text" name="userName" id="userName" v-model="userName" />
   </div>
   <button type="submit">Submit</button>
 </form>
</template>

<script>
export default {
 data() {
   return {
     userName: ""
   };
 }
};
</script>

<style>
.form {
 margin: 32px 0 0 15px;
 user-select: none;
}

.formItem {
 margin: 10px auto;
}

.formItem label {
 display: block;
}

button {
 font-size: 1em;
}
</style>
You can also try this code with Online Javascript Compiler
Run Code

 

Output

 

While inspecting this element in the chrome developer tools and opening the accessibility tab inside the elements tab, we can notice how the input gets its name from the label.
 

We can also give the input an accessible name using aria-label.

 

Code:

<template>
 <form class="form">
   <div class="formItem">
     <label for="userName">Username:</label>
     <input type="text" name="userName" id="userName" v-model="userName" :aria-label="userNameLabel"/>
   </div>
   <button type="submit">Submit</button>
 </form>
</template>

<script>
export default {
 data() {
   return {
     userName: "",
     userNameLabel: "This label takes over the accessible name"
   };
 }
};
You can also try this code with Online Javascript Compiler
Run Code

 

Output

FAQs

  1. Why is it advised to avoid using placeholders to achieve semantics in Vue?
    It is advised to avoid using placeholders to achieve semantics as it can confuse the users. This is because most placeholders don't meet the color contrast criteria and make the placeholder look like pre-populated data in the input fields. Hence, it is better to provide the information required by the user to fill out forms outside any inputs.
     
  2. How can we add instructions to the input fields?
    We can add instructions for the input fields by linking them correctly to the input. We can add additional instructions and bind multiple ids inside an aria-labelledby. Or we can attach the instructions to the input with aria-describedby.
     
  3. What is the use of aria-hidden="true"?
    It will hide the corresponding element from assistive technology but leave it visually available for the other users.
     
  4. What is the difference between aria-labelledby and aria-describedby?
    aria-labelledby is quite similar to aria-label, except it is used if the label text is visible on the screen. It is paired with other elements by their id, and we can link multiple ids.
    aria-describedby is used the same way as aria-labelledby, except that it provides a description with additional information that the user might require. This is beneficial to describe the criteria for any input.

Key Takeaways

While building modern component-based web applications in Vue, we must reach out for semantic HTML elements. This blog discussed the various ways to achieve semantics in Vue and multiple examples. And the end of the blog, we also discussed the frequently asked questions based on semantics in Vue.

 

Don't stop here. Check out our Learn Vue free course to learn Vue from scratch. Also, feel free to check out the blog Vue JS Vs. React in 2021.
 

We hope you found this blog on semantics in Vue useful. Liked the blog? Then feel free to upvote and share it.

Live masterclass