Get in touch
Thank you
We will get back to you as soon as possible
.pdf, .docx, .odt, .rtf, .txt, .pptx (max size 5 MB)

28.4.2022

4 min read

Block or inl<i>ne?

Have you ever encountered unexpected rendering issues in your HTML documents? Perhaps you've found elements behaving strangely or not displaying as intended. This common frustration often stems from incorrect nesting of HTML tags. Many people believe there are only two types of HTML tags — block and inline. However, this is a misconception. Whether you're a seasoned web developer or just starting, mastering the proper nesting of HTML elements is essential for building well-structured web pages that behave as expected. Let's get started by uncovering the root of these issues and learning how to avoid them.

Block or inl<i>ne?-1

This image contains around 50 screenshots from random articles and courses, where the authors state that tags in HTML are divided into two types - block and inline.

This is wrong.

HTML tags are divided into 7 types. In this article we will learn about them and how to use them correctly.

The Problem

Let’s imagine that we have a task where we need to make a markup of a form. Something like this:

// src/components/sign-up/components/register-form/register-form.jsx

<form className="register-form">
  <p className="register-form__control-wrapper">
    <CustomSelect label="Type:" options={[]} />
  </p>
</form>

CustomSelect markup:

// src/components/common/custom-select/custom-select.jsx

const CustomSelect = ({ label, options }) => (
  <div className="custom-select">
    <label className="custom-select__label">
      {label}
      <select className="custom-select__control">
        {options.map((it) => (
          <option value={it.value}>{it.label}</option>
        ))}
      </select>
    </label>
  </div>
);

But when we open the browser we see this:

Block or inl<i>ne?-2

Hmm, the custom select component outside of the p element? An extra p appeared?

One more example:

// src/components/sign-up/components/users/users.jsx

<div className="table-wrapper">
  <CustomTable>
    {users.map((user) => (
      <tr>
        <td>{user.name}</td>
        <td>{user.role}</td>
      </tr>
    ))}
  </CustomTable>
</div>

CustomTable markup:

// src/components/common/custom-table/custom-table.jsx

const CustomTable = ({ children }) => (
  <div className="custom-table">
    {children}
  </div>
);

Let’s open a browser:

Block or inl<i>ne?-3

What is going on…

This is how the browser behaves when we try to nest one element incorrectly within another.

7 types of HTML Element

Each element in HTML falls into zero or more categories that group elements with similar characteristics together and has its own content model and other nuances and features. For example, the p element:

Block or inl<i>ne?-4

HTML Element content types:

Block or inl<i>ne?-5

Block or inl<i>ne?-6

HTML Element content types

When you try to nest one tag in another incorrectly, browser starts fixing errors at its discretion without asking.

Let’s play. Can <x> be nested in <y>?

Open the documentation and try to find the answer yourself ?

<li>
 <p>?</p>
</li>

Yes, you can!
The li element content model — flow content.
The p element categories — flow contentpalpable content.

<header>
 <section>?</section>
</header>

Yes, you can!
The header element content model — flow content, but with no header or footer element descendants.
The section element categories — flow contentsectioning contentpalpable content.

<p>
  <div>?</div>
</p>

No, you can’t!
The p element content model — phrasing content.
The div element categories — flow contentpalpable content.

How can we test ourselves and our application? One of the tools is the official W3C validator.

You can upload the file, paste the code or use the link to your application.

Let’s try using one of our examples at the beginning of the article:

Block or inl<i>ne?-7

The result:

Block or inl<i>ne?-8

The validator and the browser did not know what we meant when we nested the <tr> element inside the <div> element. The browser tried to fix the errors itself (because of this, we got the wrong markup) and the validator talks about the stray start <tr> tag in the markup. Which is not strange since according to the documentation, the <tr> element can only be used inside the table tags (<thead><tbody><tfoot><table>).

Can I Include

Of course you don’t have to memorize all types of content but sometimes you should look there when you are not sure whether something is broken.

By analogy with Can I Use, the Can Include tool has been developed that can help us with this.

Block or inl<i>ne?-9

With this tool, we can check if we can nest one element into another.

We can check this in the official documentation but with CanInclude we can do it faster since its interface is simpler for this than the documentation.

Conclusions

HTML may break or may not look as expected and that is okay. It is not bad HTML, it just has its own rules. You just need to understand that something could break just because of incorrect nesting and know where it can be quickly checked.

Each HTML element has its own category and its own type of content that it can have. In general, there are 7 types of content that expect a certain nesting into each other.

You don’t have to memorize them all but sometimes when you have doubts or something is broken you can look at the documentation, check your code in the HTML validator or use the CanInclude tool to check yourself.

0 Comments
name *
email *