CSS display: contents and Screen Reader Accessibility
The CSS display: contents property allows developers to
remove a container element's visual box from the layout tree while
keeping its child elements intact, which is especially useful for CSS
Grid and Flexbox layouts. However, using this property frequently causes
the element—and sometimes its children—to be dropped from the browser's
accessibility tree. This article explains how
display: contents works, why it creates severe
accessibility pitfalls for screen reader users, and best practices for
avoiding layout-induced usability barriers.
What is
display: contents?
Under standard CSS box model rules, every HTML element generates a
rectangular box that influences page layout, borders, backgrounds, and
margins. When you assign display: contents to an element,
the browser essentially ignores that container’s visual box.
The element itself ceases to generate a render box, meaning its backgrounds, borders, padding, and margins are not rendered. Instead, its children are treated as if they were direct children of the element's parent.
This property was primarily introduced to simplify layout
implementations in CSS Grid and Flexbox. Developers often need wrapper
elements in the HTML for markup structure, state management, or
component boundaries, but these extra wrappers can disrupt the immediate
parent-child relationship required for grid tracks or flex alignments.
display: contents solves the layout issue without requiring
developers to alter the HTML source structure.
The Screen Reader Accessibility Problem
While the CSS specification states that
display: contents should only affect visual box generation
and not the semantic structure of a document, real-world browser
implementations have struggled to keep visual layout separate from
accessibility APIs.
Browsers construct an "accessibility tree" alongside the DOM and the render tree. Assistive technologies, including screen readers like NVDA, JAWS, and VoiceOver, rely entirely on this accessibility tree to convey context, element roles, and structural relationships to users.
Historically, many major browser rendering engines tightly coupled
their accessibility tree generation to the layout engine. Consequently,
when an element’s visual box was destroyed via
display: contents, the browser erroneously stripped the
element’s semantic meaning and role from the accessibility tree as
well.
Common Breakages
Caused by display: contents
Broken Lists: Applying
display: contentsto<ul>or<ol>elements often causes screen readers to lose list semantics. Instead of announcing "list, 4 items," the screen reader treats the inner<li>tags as plain text blocks, robbing users of vital navigation landmarks and item counting.Destroyed Table Structure: Data tables are among the most fragile elements on the web. Applying
display: contentsto<table>,<tr>,<thead>,<tbody>, or<td>elements dismantles the tabular data model. Screen readers will no longer announce row/column numbers or header associations, rendering the data incomprehensible to non-sighted users.Loss of Interactive Roles and Focus: When applied to interactive elements—such as
<button>,<fieldset>, or custom components using ARIA attributes—the browser may cease to expose the element's accessible name, role, and states. In severe cases, keyboard focus rings may become misaligned, invisible, or untargetable.Headings and Landmarks: Applying the property to semantic wrappers such as
<nav>,<main>,<aside>, or heading tags (<h1>–<h6>) can strip landmark navigation shortcuts, isolating assistive technology users from essential structural orientation.
Current Browser Status and Best Practices
Browser vendors have implemented multiple fixes over recent years to decouple accessibility semantics from the layout engine. Modern versions of Chromium, Firefox, and Safari have resolved several of the most egregious bugs regarding list and generic element semantics. However, inconsistencies remain across platforms, particularly concerning tables, ARIA landmarks, and focus management.
To maintain accessibility:
- Never apply
display: contentsto semantic HTML elements: Avoid using it on<table>,<ul>,<ol>,<button>,<select>,<nav>,<main>,<header>, or<footer>. - Restrict usage to non-semantic containers: Only use
display: contentson neutral tags like<div>or<span>that serve purely as visual styling wrappers and contain no inherent semantic roles or ARIA designations. - Test with real assistive technology: If you must
use
display: contents, verify the page in multiple screen readers (VoiceOver, NVDA, and Orca) to ensure the accessibility tree remains fully populated.