HTML

The basics

First and foremost, we make an attempt to adhere to the WordPress HTML coding standards.

Top ↑

Code style

  • HTML elements should be nested and indented logically
  • HTML elements should be properly closed
  • Indents should consist only of tabs and not spaces
  • Use lowercase for elements and attributes
  • PHP blocks are indented according to the same rules as HTML elements
  • Single line segments of PHP like our esc_html_e() call still terminate with a semi-colon

Bad

<Div class="COMPONENT">
<div class="PaRt">
<?php if ( 'met' === $condition ): ?>
  <a href="#"><?php esc_html_e( 'Follow this link', 'textdomain' ) ?></a>;
<?php endif; ?>
</Div>

Good

<div class="component">
  <div class="part">
    <?php if ( 'met' === $condition ): ?>
      <a href="#"><?php esc_html_e( 'Follow this link', 'textdomain' ); ?></a>;
    <?php endif; ?>
  </div>
</div>

Top ↑

Classes and IDs

Top ↑

CLASSES

Classes should follow the Block Element Modifier (BEM) format for naming consistency and ease of targetting in CSS. There are no hard rules for naming in BEM (other than what is provided in the link above). However, some names are better than others. This will usually come down to semantics of the HTML structure. The better the structure, the clearer the names will be.

A good example of using BEM is the product card seen below. It always follows the class name structure of block__element--modifier. The product card is the Block in BEM, with the class name product-card. It does not have an element or modifier as it is the top-level block. Child elements of the product card have classes that follow the block with two underscores and the element name. For example, we have product-card__header and product-card__content. These both follow a block__element structure. Modifiers are applied where needed, and can follow a block--modifier or block__element--modifier structure. Below, we see an example of a featured product card, with the class product-card--featured.

Bad

<div class="Product-Card">
  <header class="card_header">
    <img src="/tec-icon.png" class="product-_image" />
  </header>
  <div class="card__content">
    <h3 class="product-LABEL">The Events Calendar</h3>
    <p class="product_description">
      Easily create and manage an events calendar on your website with The Events Calendar.
      Whether your events are in-person or virtual events, this plugin boasts professional
      features backed by our world-class team of developers and designers.
    </p>
  </div>
</div>

Good

<article class="product-card">
  <header class="product-card__header">
    <img src="/tec-icon.png" class="product-card__header-image" />
  </header>
  <div class="product-card__content">
    <h3 class="product-card__label">The Events Calendar</h3>
    <p class="product-card__description">
      Easily create and manage an events calendar on your website with The Events Calendar.
      Whether your events are in-person or virtual events, this plugin boasts professional
      features backed by our world-class team of developers and designers.
    </p>
  </div>
</article>

<article class="product-card product-card--featured">
  <header class="product-card__header">
    <img src="/ecp-icon.png" class="product-card__header-image" />
  </header>
  <div class="product-card__content">
    <h3 class="product-card__label">Events Calendar Pro</h3>
    <p class="product-card__description">
      When events are your business, you need a calendar with more than the basics. Events
      Calendar Pro has all the features you need (and none of the junk you don’t).
    </p>
  </div>
</article>

When applying modifiers, they should be applied in a semantic manner. If we have a featured product card where the header and content element styles change, we should add a product-card--featured class to the product-card block rather than a product-card__header--featured and product-card__content--featured class to each of the elements that have featured styles. This implies that we could have a featured product card header without a featured product card content, and vice-versa, when they both are applied together. This also introduces a maintenance problem when the product card grows and new elements that require featured styles are introduced.

Bad

<article class="product-card">
  <header class="product-card__header product-card__header--featured">
    <img src="/tec-icon.png" class="product-card__header-image" />
  </header>
  <div class="product-card__content product-card__content--featured">
    <h3 class="product-card__label">The Events Calendar</h3>
    <p class="product-card__description">
      Easily create and manage an events calendar on your website with The Events Calendar.
      Whether your events are in-person or virtual events, this plugin boasts professional
      features backed by our world-class team of developers and designers.
    </p>
  </div>
</article>

Good

<article class="product-card product-card--featured">
  <header class="product-card__header">
    <img src="/ecp-icon.png" class="product-card__header-image" />
  </header>
  <div class="product-card__content">
    <h3 class="product-card__label">Events Calendar Pro</h3>
    <p class="product-card__description">
      When events are your business, you need a calendar with more than the basics. Events
      Calendar Pro has all the features you need (and none of the junk you don’t).
    </p>
  </div>
</article>

Top ↑

IDS

We should aim to not use the id attribute whenever possible. However, sometimes it is unavoidable due to accessibility reasons. There are no hard rules for naming IDs, but staying consistent throughout an application is important.

As BEM aims to name classes with a consistent structure, this is a great starting point for naming IDs.

Good

<article id="product-card--tec" class="product-card">
  <header class="product-card__header">
    <img src="/tec-icon.png" class="product-card__header-image" />
  </header>
  <div class="product-card__content">
    <h3 class="product-card__label">The Events Calendar</h3>
    <p class="product-card__description">
      Easily create and manage an events calendar on your website with The Events Calendar.
      Whether your events are in-person or virtual events, this plugin boasts professional
      features backed by our world-class team of developers and designers.
    </p>
  </div>
</article>

<article id="product-card--ecp" class="product-card product-card--featured">
  <header class="product-card__header">
    <img src="/ecp-icon.png" class="product-card__header-image" />
  </header>
  <div class="product-card__content">
    <h3 class="product-card__label">Events Calendar Pro</h3>
    <p class="product-card__description">
      When events are your business, you need a calendar with more than the basics. Events
      Calendar Pro has all the features you need (and none of the junk you don’t).
    </p>
  </div>
</article>

Top ↑

Attributes

Attributes should always be lowercase and within quotes, even if they are booleans or numbers. Just as with PHP or Javascript, we should strive to avoid overly-long lines of code as this can harm readability. In particular, if there are a large number of attributes for a given element then it can be desirable to break them up over multiple lines. In such a case we use the following convention:

Bad

<div id=some-id class=some-class data=1>
  <!-- Inner HTML -->
</div>

Good

<div
  id="some-id"
  class="some-class"
  data-some-data="1"
>
  <!-- Inner HTML -->
</div>

Top ↑

Semantics

HTML doesn’t just display information on a page, it conveys meaning. Semantics are important when writing HTML as it describes the structure of a page to those who may not be able to visually browse the page. BEM classes do not equal semantics, they are only names. Rather, it is the elements that create semantic structure.

Top ↑

Header and footer elements indicate specific header and footer regions.

Bad

<div class="header">
  <h1 class="title">Title</h1>
</div>
<div class="content">
  <!-- Content -->
</div>
<div class="footer">
  <span class="copyright">Copyright</span>
</div>

Good

<header>
  <h1 class="title">Title</h1>
</header>
<div class="content">
  <!-- Content -->
</div>
<footer>
  <span class="copyright">Copyright</span>
</footer>

Top ↑

The navigation element indicates a navigation region and should be used to wrap a list of menu items.

Bad

<div class="nav">
  <ul class="list">
    <li class="list-item"><a href="#">Item 1</a></li>
    <li class="list-item"><a href="#">Item 2</a></li>
    <li class="list-item"><a href="#">Item 3</a></li>
  </ul>
</div>

Good

<nav>
  <ul class="list">
    <li class="list-item"><a href="#">Item 1</a></li>
    <li class="list-item"><a href="#">Item 2</a></li>
    <li class="list-item"><a href="#">Item 3</a></li>
  </ul>
</nav>

Top ↑

Headings

Headings indicate the level of section headings and their relative importance, from h1 being the highest level to h6 being the lowest. Headings should not skip levels and there should be only one h1 per page.

Bad

<h1>Page title</h1>
<!-- content -->
<h3>Section heading</h3>
<h6>Section subheading</h6>
<!-- content -->
<h6>Section subheading</h6>
<!-- content -->
<h4>Section heading</h4>
<h2>Section subheading</h2>
<!-- content -->
<h2>Section subheading</h2>
<!-- content -->

Good

<h1>Page title</h1>
<!-- content -->
<h2>Section heading</h2>
<h3>Section subheading</h3>
<!-- content -->
<h3>Section subheading</h3>
<!-- content -->
<h2>Section heading</h2>
<h3>Section subheading</h3>
<!-- content -->
<h3>Section subheading</h3>
<!-- content -->

Top ↑

Others

There are a variety of other semantic elements that help convey meaning. These include <section><article><time><address><em>, and many others. Using the appropriate element in the proper situations will help translate useful information to those users who do not browse the page visually.

Examples

<article class="list-view__event">
  <time class="list-view__event-datetime" datetime="2020-01-01">January 1, 2020</time>
  <h3 class="list-view__event-title">New Years Party</h3>
  <address class="list-view__event-address">Times Square, New York City</address>
</article>

<section class="week-view__day-selector">
  <ul class="week-view__day-selector-list">
    <li class="week-view__day-selector-list-item">...</li>
    <li class="week-view__day-selector-list-item">...</li>
    ...
  </ul>
</section>

Top ↑

Accessibility

We strive to write accessible HTML whenever possible. This means that we use the correct HTML elements for the intended purposes. Accessible HTML is very closely linked to semantics.

Top ↑

IDs

We should aim to not use the id attribute. However, there are time when this will be unavoidable. When using the id attribute, a page cannot repeat an id more than once. This causes an accessibility violation.

Bad

<label for="name">Full name</label>
<input type="text" id="name" name="name" />
<label for="name">Pet name</label>
<input type="text" id="name" name="name" />

Good

<label for="name">Full name</label>
<input type="text" id="name" name="name" />
<label for="pet-name">Pet name</label>
<input type="text" id="pet-name" name="petName" />

Top ↑

Buttons and links are focusable interactive elements that do something when clicked or selected.

Links should be used when linking the user to another URL. They should not be used in place of a button.

Bad

<a href="#">Click me to open a modal</a>

Good

<a href="https://theeventscalendar.com/">Visit TEC</a>

Buttons are used for a target to create interactive experiences, typically using JavaScript, for the user. We do not want to replace this with a link or another element.

Bad

<a href="#">Open menu</a>

<div tabindex="0" onclick="function() { ... }">Click me</div>

Good

<button>Open menu</button>

Top ↑

Images

Images should use the alt attribute whenever possible. For users who browse the web using assistive technology, they may not be able to view the image and will receive the text within the alt attribute instead.

The exception to this is if an image is purely for decorative purposes. In this case, an empty alt attribute will convey this meaning.

Bad

<img src="/cute-puppy.jpg" />

Good

<img src="/cute-puppy.jpg" alt="cute puppy playing with toy." />

<img src="/border-line.jpg" alt="" />

Top ↑

Forms

Forms are complex HTML structures that require a bit of attention to make them accessible. Fortunately, these are fairly easy to implement.

Top ↑

INPUTS AND LABELS

Form inputs should have labels linked to them in order to convey this information properly to those using assistive technology. This can be done by setting an id attribute on the input and using the same value in the for attribute of the label.

Bad

<label>Full Name</label>
<input type="text" name="name" />

Good

<label for="full-name">Full Name</label>
<input type="text" id="full-name" name="name" />

Top ↑

PLACEHOLDERS

Placeholders may visually look like a label, but do not convey the same information as a label. For this reason, we always want a label associated with a form input.

Bad

<input type="tel" name="phone" placeholder="123-456-7890" />

Good

<label for="phone">Phone</label>
<input type="tel" id="phone" name="phone" placeholder="123-456-7890" />

Top ↑

BUTTONS AND SUBMIT

A form should have a submit button to allow users to submit the information entered into the form. A form can also have buttons for custom functionality. Properly identifying the type of button is important not just in terms of functionality but also accessibility.

When a button is placed within a form without the type attribute, the default value is submit and the form will submit when the button is clicked. To prevent this, always add a type attribute when adding a button to a form.

Good

<button class="form__submit-button" type="submit">Submit</button>
<button class="form__reset-button" type="reset">Reset</button>
<button class="form__custom-button" type="button">I will not submit the form</button>

Top ↑

FIELDSETS AND LEGENDS

Fieldsets are used to group related fields and labels together. A legend is used to label the fieldset and is required for accessibility. Fieldsets are not required in forms, but can be semantically useful for grouping related form inputs together.

Bad

<fieldset>
  <label for="full-name">First Name</label>
  <input type="text" id="full-name" name="fullName" />
  <label for="date-of-birth">Date of birth</label>
  <input type="date" id="date-of-birth" name="dob" min="1900-01-01" max="2019-12-31" />
</fieldset>

Good

<fieldset>
  <legend>Personal information</legend>
  <label for="full-name">First Name</label>
  <input type="text" id="full-name" name="fullName" />
  <label for="date-of-birth">Date of birth</label>
  <input type="date" id="date-of-birth" name="dob" min="1900-01-01" max="2019-12-31" />
</fieldset>

Top ↑

Headings

As mentioned above in the semantics section, headings indicate the level of section headings and their relative importance. Headings should not skip levels and there should be only one h1 per page.

Top ↑

ARIA Attributes

Accessible Rich Internet Applications (ARIA) attributes help make applications, especially those using JavaScript functionality, more accessible to those using assistive technology. They supplement the existing HTML and are not meant to replace the built-in attributes.

Top ↑

DISABLED AND REQUIRED

When using HTML form inputs, we may use the disabled and required attributes depending on the situation. There are also, however, ARIA attributes with the same names: aria-disabled and aria-required. With HTML5, we can now use the disabled and required attributes and do not need these ARIA attributes.

Bad

<label for="full-name">Full Name</label>
<input type="text" id="full-name" name="name" aria-required="true" />

<label for="phone">Phone</label>
<input type="tel" id="phone" name="phone" placeholder="123-456-7890" aria-disabled="true" />

Good

<label for="full-name">Full Name</label>
<input type="text" id="full-name" name="name" required />

<label for="phone">Phone</label>
<input type="tel" id="phone" name="phone" placeholder="123-456-7890" disabled />

Top ↑

HIDDEN, EXPANDED, AND CONTROLS

The ARIA attributes aria-hiddenaria-expanded, and aria-controls often work in combination with each other. This combination is often used for an accordion pattern or a custom dropdown pattern and changed using JavaScript. These attributes allow the user using assistive technology to understand how elements are linked together and what state they are in.

Bad

<button>Accordion header</button>
<div class="u-hidden">
  <span>Accordion content</span>
</div>

Good

<button
  id="accordion-header"
  aria-controls="accordion-content"
  aria-expanded="false"
>
  Accordion header
</button>
<div
  class="u-hidden"
  id="accordion-content"
  aria-hidden="true"
  aria-labelledby="accordion-header"
>
  <span>Accordion content</span>
</div>

Top ↑

LABEL AND LABELLEDBY

The ARIA attributes aria-label and aria-labelledby allow the user using assistive technology to receive an explanation associated with a specific element, much like a label would provide.

Bad

<!-- Navigations require a label to describe it -->
<nav>
  <!-- Navigation list -->
</nav>

<!-- Buttons require text to announce to assistive technology -->
<button>
  <svg><!-- SVG icon --></svg>
</button>

Good

<nav aria-label="Primary Navigation">
  <!-- Navigation list -->
</nav>

<nav aria-labelledby="main-nav-heading">
  <h2 id="main-nav-heading" class="u-visual-hide">Primary Navigation</h2>
  <!-- Navigation list -->
</nav>

<!-- Using visually-hidden text is usually the best option here -->
<button>
  <svg><!-- SVG icon --></svg>
  <span class="u-visual-hide">Close menu</span>
</button>

<!-- In cases where visually-hidden text is not possible -->
<button aria-label="Close menu">
  <svg><!-- SVG icon --></svg>
</button>

Top ↑

Security

Top ↑

Anchor tags

When adding a new anchor tag with a target="_blank" attribute, simply adding that attribute adds an additional attack vector for folks with compromised site content.

For our plugins, we must be sure to add rel="noopener noreferrer" to anchor tags that make use of target="_blank".

Bad

<a href="https://theeventscalendar.com" target="_blank">TEC</a>

Good

<a href="https://theeventscalendar.com" target="_blank" rel="noopener noreferrer">TEC</a>