Divs are bad!

posted on

Yes, clickbait, I’m so sorry! Of course, divs are not bad. For example, they can be really useful,…

Even though there’s nothing wrong with the div per se, some people, including me, still like to complain when they’re not used consciously.

The issue with divs is not the quantity, although a large DOM can affect performance negatively, and an unnecessarily large document is harder to read and debug. The real problem is the placement. If you put a div in the wrong place, it can have serious negative side effects.

Here are some examples:

details and summary

If you wrap the contents of a details element in a div, the browser or a screen reader might not recognize the summary element properly and display and announce a fallback text instead.

Wrong

<details>
  <div>
    <summary>Show info</summary>
    Hi, I'm the info!
  </div>
</details>
Show info Hi, I'm the info!

Right

<details>
  <summary>Show info</summary>
  Hi, I'm the info!
</details>
Show info Hi, I'm the info!

figure

If you wrap the contents of a figure element in a div, the figcaption might not be recognized as the caption for the figure. Visually this probably has no effect, but the figure might not be exposed to assistive technology when it doesn't have an accessible name.

Wrong

<figure>
  <img src="/images/gus.jpg" width="400" alt="Gus Polinski.">

  <div>
    <figcaption>
      The Polka King of the Midwest talking to a desperate mother.
    </figcaption>
  </div>
</figure>
Gus Polinski, the Polka King of the Midwest talking to a desperate mother.
The Polka King of the Midwest talking to a desperate mother.

Right

<figure>
  <img src="/images/gus.jpg" width="400" alt="Gus Polinski.">

  <figcaption>
    The Polka King of the Midwest talking to a desperate mother.
  </figcaption>
</figure>
Gus Polinski
The Polka King of the Midwest talking to a desperate mother.

fieldsets

A fieldset gets its label from the legend element. If the legend is wrapped in a div, the fieldset has no accessible name. This may cause the group of radio buttons not being announced as a group and the legend might not have a sematic relation with the radio buttons. The visual appearance breaks as well. The legend isn’t positioned on the border of the fieldset, but below it.

Wrong

<fieldset>
  <div>
    <legend>Shirt sizes</legend>

    <div>
      <input type="radio" id="l" name="shirt1">
      <label for="l">Large</label>
    </div>
    <div>
      <input type="radio" id="m" name="shirt1">
      <label for="m">Medium</label>
    </div>
  </div>
</fieldset>
Shirt sizes

Right

<fieldset>
  <legend>Shirt sizes</legend>

  <div>
    <input type="radio" id="l2" name="shirt2">
    <label for="l2">Large</label>
  </div>
  <div>
    <input type="radio" id="m2" name="shirt2">
    <label for="m2">Medium</label>
  </div>
</fieldset>
Shirt sizes

lists

ul and ol must only directly contain li, script or template elements. Wrapping all list items in a div may change the way list items get announced by a screen reader.

Wrong

<ul>
  <div>
    <li>A</li>
    <li>B</li>
    <li>C</li>
  </div>
</ul>

Right

<ul>
  <li>A</li>
  <li>B</li>
  <li>C</li>
</ul>

A quick side note: It’s fine to use divs in a definition list (dl).

Right

<dl>
  <div>
    <dt>Key:</dt>
    <dd>Value</dd>
  </div>
  <div>
    <dt>Key:</dt>
    <dd>Value</dd>
  </div>
</dl>
Key:
Value
Key:
Value

paragraphs

If you put a div in a p, it breaks the paragraph. For example, it could cause the browser to close the paragraph implicitly, render the content outside of it, and add another paragraph.

This is especially evident, if you try to style the paragraph, e.g. by adding a red border.

p {
  border: 2px solid red;
}

Wrong

<p>
  <div>I'm wrapped in a div.</div>
  I'm not wrapped in a div.
</p>

May result in:

<p></p>
<div>I'm wrapped in a div.</div>
I'm not wrapped in a div.
<p></p>

I'm wrapped in a div.
I'm not wrapped in a div.

Right

<p>
  I'm wrapped in a div.<br>
  I'm not wrapped in a div.
</p>

I'm wrapped in a div.
I'm not wrapped in a div.


I’ve seen all these wrong implementations (or variations of them) on several websites.

How do we prevent that?

Before launching a site, when you deploy changes to an existing component or page or when you add a new component, validate the rendered markup. You can use the validation bookmarklet by Deque for that. It works both with server- and client-side rendered pages.

If you’re working with a JavaScript library or framework that demands that you wrap all items within the component in a parent element, before immediately going for the div, check first if you can use a fragment instead or if there’s a more suitable semantic element you could use.