Need help with your JSON?
Try our JSON Formatter tool to automatically identify and fix syntax errors in your JSON. JSON Formatter tool
Reading Order Optimization for Screen Readers in JSON Views
Displaying raw or processed JSON data in a user interface is a common task. While visually appealing formatting with indentation and syntax highlighting helps sighted users, it often creates significant barriers for users who rely on screen readers. Screen readers interpret web pages based on the underlying HTML structure and its semantic meaning, not its visual layout. A poorly structured JSON view can result in a confusing, illogical, or non-navigable experience.
This article explores the challenges screen readers face with typical JSON representations and provides strategies using semantic HTML and ARIA attributes to improve the reading order and overall accessibility of JSON data displays.
The Problem with Visual JSON Views
Consider a typical visually formatted JSON object:
{
"name": "Alice",
"age": 30,
"isStudent": false,
"address": {
"street": "123 Main St",
"city": "Anytown"
},
"courses": ["Math", "Science", "History"]
}
Sighted users quickly understand the structure through indentation, brackets (`{}`, `[]`), and commas. A screen reader, however, reads the underlying HTML. If this is merely rendered as a flat sequence of `<span>` or `<div>` elements with styles for indentation and color, a screen reader might read:
"Open brace name colon Alice comma age colon 30 comma isStudent colon false comma address open brace street colon 123 Main St comma city colon Anytown close brace comma courses open bracket Math comma Science comma History close bracket close brace."
This linear reading can be extremely difficult to parse mentally, especially for complex or deeply nested JSON. Users lose the hierarchical context and the relationship between keys and values.
Understanding Screen Reader Reading Order
Screen readers typically navigate a web page in DOM order (the order elements appear in the HTML). They process elements like headings, paragraphs, lists, and form controls, often allowing users to jump between these element types. Semantic HTML elements convey meaning and structure (e.g., `<ul>` is a list, `<h2>` is a subheading, `<button>` is interactive).
To optimize a JSON view, we need to translate its visual structure into a semantic structure that screen readers can understand and navigate effectively.
Common Accessibility Issues in JSON Views
- Lack of Hierarchy: Visual indentation is ignored, flattening the structure.
- Meaningless Punctuation: Braces, brackets, and commas are read literally without conveying their structural role (object start/end, array item separation).
- Key-Value Association: It can be hard to tell which value belongs to which key, especially in long lists or nested objects.
- Data Type Ambiguity: Screen readers don't inherently announce the type of a value (string, number, boolean, null, array, object) unless explicitly marked.
- Unnecessary Noise: Decorative characters or excess formatting read out loud.
Optimization Strategies using Semantic HTML and ARIA
The goal is to use HTML elements that carry semantic meaning appropriate for the JSON structure, and supplement them with ARIA attributes where native semantics are insufficient.
Objects (`{}`)
JSON objects are collections of key-value pairs. The HTML Description List (`<dl>`) is the most semantically appropriate element for this structure.
- Use `<dl>` for the object wrapper.
- Use `<dt>` for each key (Definition Term).
- Use `<dd>` for each value (Definition Description).
Example (using the previous JSON):
Accessible Object Rendering with `<dl>`
<dl className="json-object"> <dt>name</dt> <dd>"Alice"</dd> <dt>age</dt> <dd>30</dd> <dt>isStudent</dt> <dd>false</dd> <dt>address</dt> <dd> {/* Nested Object: Use another DL */} <dl className="json-object"> <dt>street</dt> <dd>"123 Main St"</dd> <dt>city</dt> <dd>"Anytown"</dd> </dl> </dd> <dt>courses</dt> <dd> {/* Nested Array: Use UL */} <ul className="json-array"> <li>"Math"</li> <li>"Science"</li> <li>"History"</li> </ul> </dd> </dl>
A screen reader encountering this structure will announce "Description list" or similar, then read "name", followed by "definition, Alice". It provides clear key-value pairing. Nested objects and arrays maintain their structure by using nested `<dl>` and `<ul>`.
Arrays (`[]`)
JSON arrays are ordered lists of values. The HTML Unordered List (`<ul>`) is the semantic choice here.
- Use `<ul>` for the array wrapper.
- Use `<li>` for each item in the array.
Example:
Accessible Array Rendering with `<ul>`
<ul className="json-array"> <li>"Math"</li> <li>"Science"</li> <li>"History"</li> {/* Arrays can contain objects/arrays too */} <li> <dl className="json-object"> <dt>level</dt> <dd>"advanced"</dd> </dl> </li> </ul>
A screen reader will announce "List with 3 items" (or similar), and then read each item. This allows users to understand it's a collection and navigate item by item.
Adding Context with ARIA
While `<dl>` and `<ul>` provide good structural semantics, additional context can be helpful.
- `aria-label` / `aria-labelledby`: Use on containers (`<dl>`, `<ul>`) to give a meaningful label if the context isn't clear from the surroundings (e.g., `aria-label="User Details Object"`). You could also label the object/array using the key name from the parent object if applicable.
- `role="group"`: Sometimes, you might wrap related elements (like a complex value or a nested structure not perfectly fitting `dl`/`ul`) in a `<div role="group" aria-label="...">` to explicitly group them for screen readers. However, prefer native semantic elements first.
- Value Type Announcement: For clarity, you might structure the `<dd>` or `<li>` to explicitly state the type, although this can become verbose. E.g., `<dd><span className="sr-only">string</span>"Alice"</dd>`. A less verbose approach is often sufficient if the context is clear.
Collapsible Sections (Objects/Arrays)
For very large or deeply nested JSON, allowing users to collapse sections improves navigation and reduces cognitive load. Use standard disclosure pattern semantics.
- Wrap the object or array `<dl>` or `<ul>` in a container.
- Provide a button or interactive element to toggle visibility.
- The interactive element should have `aria-expanded="true"` or `aria-expanded="false"`.
- The collapsible content container should have an `id`.
- The interactive element should have `aria-controls="[id_of_content]"`.
- Manage the visibility of the content (e.g., using CSS `display: none` or `visibility: hidden`).
Example structure (simplified):
Collapsible Object/Array Structure
<div> {/* Container */} <button aria-expanded="true" aria-controls="details-content"> {/* Key name or label for the object/array */} address: {...} {/* Visual representation */} </button> <div id="details-content"> {/* Collapsible content */} <dl className="json-object"> <dt>street</dt> <dd>"123 Main St"</dd> <!-- ... other key-value pairs ... --> </dl> </div> </div>
Screen readers will announce the button's label and its expanded/collapsed state, allowing users to navigate the structure at a high level before diving into the details.
Handling Primitive Types (string, number, boolean, null)
These are the values within `<dd>` or `<li>` elements.
- Strings: Display the string value. Ensure quotes are either removed visually/audibly or semantically marked if they are part of the actual data. Often, just the string content is best.
- Numbers: Display the number.
- Booleans: Display "true" or "false". Ensure they are readable as boolean values.
- Null: Display "null".
Avoid displaying JSON syntax characters (`"`, `:`, `,`) unless they are part of the data itself. The semantic HTML structure (`<dt>`, `<dd>`, `<li>`) provides the necessary context.
Hiding Decorative Elements
Visual elements used purely for structure or decoration (like the literal `` or `[]` if not part of the navigable structure, or connecting lines in a tree view) should be hidden from screen readers using `aria-hidden="true"`.
<span aria-hidden="true">{</span> {/* Hide decorative brace */} <dl> <dt>key</dt><span aria-hidden="true">:</span> {/* Hide decorative colon */} <dd>value</dd> </dl> <span aria-hidden="true">}</span> {/* Hide decorative brace */}
A More Complete TSX Example Structure
Putting it together, a recursive component structure could render JSON accessibly. Below is a conceptual outline (actual implementation would handle rendering different types recursively).
Conceptual Recursive JSON Renderer Structure (TSX)
// Assumes 'data' is your parsed JSON object/array // Assumes 'key' is the key name if rendering a value within an object // Assumes 'label' is a descriptive label if needed for a container (e.g., "Root JSON Object") function renderJsonValue(value: any, key?: string, label?: string): JSX.Element { if (value === null) { return <span className="json-null">null</span>; } switch (typeof value) { case 'string': return <span className="json-string">"{value}"</span>; // Or just {value} without quotes case 'number': return <span className="json-number">{value}</span>; case 'boolean': return <span className="json-boolean">{value.toString()}</span>; case 'object': if (Array.isArray(value)) { // Render Array return ( <ul className="json-array" aria-label={label || key ? `${key || ''} Array` : undefined}> {value.map((item, index) => ( <li key={index}> {renderJsonValue(item)} {/* Recursively render array item */} </li> ))} </ul> ); } else { // Render Object const objectKeys = Object.keys(value); return ( <dl className="json-object" aria-label={label || key ? `${key || ''} Object` : undefined}> {objectKeys.map(objKey => ( <React.Fragment key={objKey}> <dt className="json-key">{objKey}</dt> <dd className="json-value"> {renderJsonValue(value[objKey], objKey)} {/* Recursively render value */} </dd> </React.Fragment> ))} </dl> ); } default: return <span>Unsupported Type</span>; // Should not happen with valid JSON } } // In your page component's render function: // Assume 'jsonData' is the JSON object you want to display // <div> // <h3>JSON Data View</h3> // {renderJsonValue(jsonData, undefined, "Root JSON Data")} // </div>
This recursive approach naturally builds the nested `<dl>` and `<ul>` structure that aligns with screen reader expectations, providing a logical reading order and clear relationship between keys and values. Adding `aria-label` to the containers gives context at each level of nesting.
Additional Considerations
- Keyboard Navigation: Ensure that if sections are collapsible, they are navigable and controllable via keyboard (Tab, Enter, Space).
- Focus Management: When expanding/collapsing, consider where focus should move, especially in complex views.
- Alternative Views: For very large or deeply complex JSON, consider providing alternative views like a searchable flat list of paths/values or a dedicated tree-view component with robust accessibility features.
- Consistent Styling: Use CSS to style the `<dl>`, `<dt>`, `<dd>`, `<ul>`, and `<li>` elements to match your application's visual design. You can visually hide the list markers or indentation if desired, as long as the semantic structure remains.
Conclusion
Simply displaying JSON text with visual formatting is insufficient for users who rely on screen readers. By translating the JSON structure into appropriate semantic HTML elements (`<dl>` for objects, `<ul>` for arrays) and augmenting with ARIA attributes like `aria-label` and `aria-expanded`, developers can create JSON views that are not only visually understandable but also logically structured and easily navigable by assistive technologies. Prioritizing semantic structure ensures that the intended reading order and relationships within the data are clearly communicated to all users.
Need help with your JSON?
Try our JSON Formatter tool to automatically identify and fix syntax errors in your JSON. JSON Formatter tool