Avoid overusing div elements in React components
When looking over React code, I often see div
elements being overused in React components. In HTML, the div
element is short for division, and it can represent any type of block-level division on a page. Using div
elements for everything is not wrong, but it's not great either.
A block-level HTML element always starts on a new line and always takes up the full width available.
The div
element has been around for a while. It's become the go-to element of choice when we need to wrap some content in a block for layout or styling purposes. Since the div
element is the most generic HTML element, it's easy to end up overusing it.
Consider the following React component that uses div
elements for almost everything.
const App = () => {
return (
<div className="layout">
<div className="header">
<div className="title">My blog</div>
<div className="navigation">
<a href="/">Home</a>
<a href="/about">About</a>
<a href="/contact">Contact</a>
</div>
</div>
<div className="main">
<div className="intro">
Welcome to my blog.
</div>
<div className="content">
<div className="article">
<div id="article-header">
<h3>My blog post</h3>
</div>
<p>Read more</p>
</div>
<div className="related">
<h3>Related posts</h3>
</div>
</div>
</div>
<div className="footer">
Contact us!
</div>
</div>
)
}
export { App }
That's a lot of div
elements! There's nothing technically wrong with the HTML code above. It works fine. It can be styled as needed using the class names that are applied to the div
elements. However, there are some serious concerns with this approach.
Issues with overusing div elements
The HTML Spec advises us to use div
element as a last resort.
Authors are strongly encouraged to view the div element as an element of last resort, for when no other element is suitable. Use of more appropriate elements instead of the div element leads to better accessibility for readers and easier maintainability for authors.
Accessibility
A div
is just a block-level wrapper. div
tags don't communicate useful information about the structure of a web page.
a11y
tools try their best to parse the structure of a web page and find meaning in that structure. However, div
tags communicate nothing to a11y
tools. They don't provide any meaning as to what sort of content one could expect to find in a given div
.
As developers, we can recognize that an element with an id
of article-header
is intended to be the header of a blog article, but robots can't recognize that.
Readability
The code above is hard to read. It's very busy, with lots of HTML elements and class names. To make sense of each element, we must read through all the markup and get to the class names - which gives us an indication of what each element is for.
The nesting of div
tags makes it hard to know what level of the element hierarchy we're currently reading. It also makes it hard to see if we missed an opening or closing tag.
Not standards-compliant
If only there was a standardized way to understand the purpose of each element on a web page - rather than just knowing it's a division. There now is a way! This way was provided to us with HTML 5. Using div
tags everywhere was fine when HTML 4 was still around. However, the standards-compliant markup that powers the web is now HTML 5.
One of the great advancements that HTML 5 introduced was a standardized set of semantic elements.
Semantic elements to the rescue
The term semantic refers to the meaning of a word. Semantic elements allow us to structure our web pages in a more meaningful way. When we use a semantic element, we make it's purpose on the web page clear. Semantic elements are standardized as of HTML 5, which means they define a web page layout in a way that everyone can understand, including robots.
Semantic HTML is all about using the right HTML elements for their right purpose. Sure, we can use a combination of CSS and JavaScript to make any HTML element behave however we want. We can use a div
element for a button instead of using a button
element, for example. However, this is not semantic HTML.
Besides accessibility, the benefits of semantic HTML are:
- Easier to develop with.
- Easier to understand.
- Results in less HTML elements, thus, a smaller file size.
- Better for SEO.
When it comes to semantic HTML and SEO, search engines give more importance to keywords inside headings, links, etc, rather than keywords in non-semantic div
elements.
Best of all, semantic HTML is not more complex to write than non-semantic HTML. If semantic HTML is used consistently across a project, there will be less refactoring to do later on.
Layouts with semantic HTML
When writing on a page, we usually divide that page into three areas: a header, a main content area, and a footer. The main content area is then divided into various sections. The same is true for semantic HTML.
Rather than creating a layout with only nested div
elements, we can select more semantically appropriate HTML 5 elements. These elements will provided extra details to screen readers (and other robots) regarding the content that is being navigated.
Let's take a look at the semantic HTML 5 elements for web page layouts.
HTML 5 header element
The header
element is for introductory content, titles, or a container navigation elements of a section or page.
<header>
<h1>Welcome</h1>
</header>
HTML 5 nav element
The nav
element is for navigation links.
<nav>
<ul>
<li>
<a href="/">Home</a>
</li>
<li>
<a href="/about">About</a>
</li>
</ul>
</nav>
HTML 5 article element
The article
element is for self-contained content that can be independently distributed. An article
should make sense on its own.
<article>
<h3>Blog Post Title</h3>
<p>Content...</p>
</article>
HTML 5 section element
The section
element is for a standalone section or a grouping of content.
<section>
<h2>Contact Us</h2>
<p>Send a message</p>
</section>
HTML 5 aside element
The aside
element is for accompanying content that is related to the main content, such as sidebars.
<aside>
<h3>Related Articles</h3>
<ul>
<li>Article 1</li>
<li>Article 2</li>
</ul>
</aside>
HTML 5 footer element
The footer
element is for the the closing section of a section or page.
<footer>© My Website.</footer>
HTML 5 main element
The main
element is for the main content of a page.
<header>
My Site
</header>
<main>
<h1>My page</h1>
<p>My page content</p>
</main>
<footer>
© My Website.
</footer>
The HTML Spec indicates that we should not include more than one main
element in a document. We should not include the main
element as a child of an article
, aside
, footer
, header
or nav
element.
Fixing the non-semantic HTML
With these semantic layout elements now in our HTML tool belt, let's re-visit the non-semantic example we saw above. We'll convert the div
elements to semantic ones.
import { ReactNode } from "react";
type LayoutProps = {
children?: ReactNode;
}
const Layout = ({ children }: LayoutProps) => {
return (
<>
<header>
<h1>My blog</h1>
<nav>
<a href="/">Home</a>
<a href="/about">About</a>
<a href="/contact">Contact</a>
</nav>
</header>
<main>
{children}
</main>
<footer>
Contact us!
</footer>
</>
)
}
const App = () => {
return (
<Layout>
<section className="welcome">
Welcome to my blog.
</section>
<section className="posts">
<article>
<header>
<h3>My blog post</h3>
</header>
<p>Read more</p>
</article>
<aside>
<h3>Related posts</h3>
</aside>
</section>
</Layout>
)
}
export { App }
No more div
elements! We were able to replace them all with semantic HTML elements.
For the top-most wrapping element, we introduced a Layout
React component that makes use of the React children
prop to render page content with a specific layout. This approach keeps the header, footer, and main content areas consistent across the entire site. It's great for theming and templating. The header
and footer
elements within the Layout
component could also be moved to their own respective Header
and Footer
components.
We removed the class names and ids from the HTML elements. We only added class names where we need to distinguish between identical siblings. We had two sibling section
elements, so we gave them a class name each. This will allow us to style them independently.
The result is an App
component that is easier for developers and screen readers to read and understand.