aria-level
Defines the hierarchical level of an element within a structure. Essential for headings when native HTML elements can't be used, and for tree structures to indicate nesting depth.
Overview
The aria-level attribute defines an element's hierarchical level within a structure. It's primarily used with role="heading" and role="treeitem".
The value must be an integer โฅ 1. For headings, levels 1-6 correspond to h1-h6. For tree items, the level indicates nesting depth (1 = root, 2 = child, etc.).
Prefer Native Elements
Always prefer native HTML elements like <h1>-<h6> when possible. Only use role="heading" with aria-level when native elements aren't feasible.
Live Demo: Tree Structure
- โผ๐Documents(level 1)
- โผ๐Projects(level 2)
- ๐report.pdf(level 3)
- ๐notes.txt(level 3)
- โถ๐Images(level 1)
Screen reader: "Documents, tree item, level 1, expanded". "Projects, tree item, level 2, expanded". "report.pdf, tree item, level 3".
Code Examples
Heading Levels
<!-- aria-level for heading hierarchy -->
<!-- Custom heading with explicit level -->
<div role="heading" aria-level="1">
Main Page Title
</div>
<div role="heading" aria-level="2">
Section Title
</div>
<div role="heading" aria-level="3">
Subsection Title
</div>
<!-- Screen reader: "Main Page Title, heading level 1" -->
<!-- Semantic HTML is preferred when possible -->
<h1>Main Title</h1> <!-- Level 1 implicit -->
<h2>Section Title</h2> <!-- Level 2 implicit -->
<h3>Subsection</h3> <!-- Level 3 implicit -->
<!-- Use aria-level only when you can't use native headings -->Tree Structure
<!-- aria-level for tree structure -->
<ul role="tree" aria-label="File System">
<!-- Level 1 items -->
<li role="treeitem" aria-level="1" aria-expanded="true">
๐ Documents
<ul role="group">
<!-- Level 2 items -->
<li role="treeitem" aria-level="2" aria-expanded="true">
๐ Projects
<ul role="group">
<!-- Level 3 items -->
<li role="treeitem" aria-level="3">๐ report.pdf</li>
<li role="treeitem" aria-level="3">๐ notes.txt</li>
</ul>
</li>
<li role="treeitem" aria-level="2">๐ todo.md</li>
</ul>
</li>
<li role="treeitem" aria-level="1">
๐ Images
</li>
</ul>
<!-- Screen reader announces depth: "Documents, tree item, level 1, expanded" -->Nested Tabs
<!-- aria-level for nested tab structures -->
<div class="nested-tabs">
<!-- Primary tabs (level 1) -->
<div role="tablist" aria-label="Main sections">
<button role="tab" aria-selected="true" aria-level="1">
Account
</button>
<button role="tab" aria-selected="false" aria-level="1">
Settings
</button>
</div>
<!-- Secondary tabs within Account (level 2) -->
<div role="tabpanel">
<div role="tablist" aria-label="Account sections">
<button role="tab" aria-selected="true" aria-level="2">
Profile
</button>
<button role="tab" aria-selected="false" aria-level="2">
Security
</button>
</div>
</div>
</div>React Components
// React Tree Component with aria-level
import { useState } from 'react';
function TreeItem({ item, level = 1 }) {
const [expanded, setExpanded] = useState(false);
const hasChildren = item.children && item.children.length > 0;
return (
<li
role="treeitem"
aria-level={level}
aria-expanded={hasChildren ? expanded : undefined}
aria-selected={item.selected}
>
<div
className="tree-item-content"
onClick={() => hasChildren && setExpanded(!expanded)}
style={{ paddingLeft: `${(level - 1) * 20}px` }}
>
{hasChildren && (
<span className="expand-icon">
{expanded ? 'โผ' : 'โถ'}
</span>
)}
<span className="item-icon">{item.icon}</span>
<span className="item-label">{item.label}</span>
</div>
{hasChildren && expanded && (
<ul role="group">
{item.children.map((child, index) => (
<TreeItem
key={index}
item={child}
level={level + 1}
/>
))}
</ul>
)}
</li>
);
}
function FileTree({ data }) {
return (
<ul role="tree" aria-label="File browser">
{data.map((item, index) => (
<TreeItem key={index} item={item} level={1} />
))}
</ul>
);
}
// Custom Heading Component
function Heading({ level, children, ...props }) {
// Prefer semantic elements when possible
const Tag = level <= 6 ? `h${level}` : 'div';
if (level <= 6) {
return <Tag {...props}>{children}</Tag>;
}
// For levels > 6, use aria-level
return (
<div role="heading" aria-level={level} {...props}>
{children}
</div>
);
}
// Usage
function DocumentOutline() {
const files = [
{
label: 'Documents',
icon: '๐',
children: [
{ label: 'report.pdf', icon: '๐' },
{ label: 'notes.txt', icon: '๐' }
]
},
{
label: 'Images',
icon: '๐',
children: [
{ label: 'photo.jpg', icon: '๐ผ๏ธ' }
]
}
];
return (
<div>
<Heading level={1}>File Browser</Heading>
<FileTree data={files} />
</div>
);
}
