or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

async-utilities.mdasync.mdconfig.mdconfiguration.mddebugging.mdevents.mdindex.mdqueries.mdquery-helpers.mdrole-utilities.mdscreen.mdutilities.mdwithin.md

role-utilities.mddocs/

0

# Role Utilities

1

2

Work with ARIA roles and the accessibility tree to understand how assistive technologies perceive your UI.

3

4

## getRoles

5

6

Get all ARIA roles in a container mapped to their elements.

7

8

```typescript

9

function getRoles(container: HTMLElement): {

10

[index: string]: HTMLElement[];

11

};

12

```

13

14

Usage:

15

```javascript

16

import {getRoles} from '@testing-library/dom';

17

18

// Get all roles

19

const roles = getRoles(document.body);

20

// { button: [<button>, <button>], heading: [<h1>], link: [<a>, <a>] }

21

22

// Check specific role

23

const mainRoles = getRoles(document.body);

24

if (mainRoles.button) {

25

console.log(`Found ${mainRoles.button.length} buttons`);

26

}

27

28

// Get all elements with specific role

29

const allButtons = getRoles(document.body).button || [];

30

allButtons.forEach(button => console.log('Button:', button.textContent));

31

32

// In specific container

33

const nav = screen.getByRole('navigation');

34

const navRoles = getRoles(nav);

35

```

36

37

## logRoles

38

39

Log all roles with their elements to console.

40

41

```typescript

42

function logRoles(

43

container: HTMLElement,

44

options?: {hidden?: boolean}

45

): string;

46

```

47

48

Usage:

49

```javascript

50

import {logRoles, screen} from '@testing-library/dom';

51

52

// Log all roles

53

logRoles(document.body);

54

// Output:

55

// button:

56

// <button>Submit</button>

57

// heading:

58

// <h1>Welcome</h1>

59

60

// Include hidden elements

61

logRoles(document.body, {hidden: true});

62

63

// Capture output

64

const output = logRoles(document.body);

65

```

66

67

## isInaccessible

68

69

Check if element is inaccessible (hidden from screen readers).

70

71

```typescript

72

function isInaccessible(element: Element): boolean;

73

```

74

75

Usage:

76

```javascript

77

import {isInaccessible, screen} from '@testing-library/dom';

78

79

// Check accessibility

80

const button = screen.getByRole('button');

81

console.log('Is inaccessible:', isInaccessible(button)); // false

82

83

const hiddenDiv = document.getElementById('hidden-content');

84

console.log('Is inaccessible:', isInaccessible(hiddenDiv)); // true

85

86

// Filter accessible elements

87

const allElements = Array.from(document.querySelectorAll('*'));

88

const accessibleElements = allElements.filter(el => !isInaccessible(el));

89

90

// Validate in tests

91

test('content is accessible', () => {

92

const mainContent = document.getElementById('main-content');

93

expect(isInaccessible(mainContent)).toBe(false);

94

});

95

```

96

97

## computeHeadingLevel

98

99

Get heading level (1-6) from tag or aria-level.

100

101

```typescript

102

function computeHeadingLevel(element: Element): number | undefined;

103

```

104

105

Usage:

106

```javascript

107

import {computeHeadingLevel, screen} from '@testing-library/dom';

108

109

// From tag

110

const heading = document.querySelector('h1');

111

console.log(computeHeadingLevel(heading)); // 1

112

113

// From aria-level

114

const customHeading = document.querySelector('[role="heading"][aria-level="3"]');

115

console.log(computeHeadingLevel(customHeading)); // 3

116

117

// Validate heading hierarchy

118

test('proper structure', () => {

119

const headings = screen.getAllByRole('heading');

120

const levels = headings.map(computeHeadingLevel);

121

122

expect(levels[0]).toBe(1); // First heading is h1

123

124

// No skipped levels

125

for (let i = 1; i < levels.length; i++) {

126

expect(levels[i]).toBeLessThanOrEqual(levels[i - 1] + 1);

127

}

128

});

129

130

// Filter by level

131

const allHeadings = screen.getAllByRole('heading');

132

const h1Headings = allHeadings.filter(h => computeHeadingLevel(h) === 1);

133

const h2Headings = allHeadings.filter(h => computeHeadingLevel(h) === 2);

134

```

135

136

## Common Patterns

137

138

### Understanding Available Roles

139

140

```javascript

141

import {getRoles, logRoles} from '@testing-library/dom';

142

143

// Quick overview

144

logRoles(document.body);

145

146

// Or programmatically

147

const roles = getRoles(document.body);

148

Object.keys(roles).forEach(roleName => {

149

console.log(`${roleName}: ${roles[roleName].length} elements`);

150

});

151

```

152

153

### Debugging Query Failures

154

155

```javascript

156

import {logRoles, screen} from '@testing-library/dom';

157

158

test('find button', () => {

159

try {

160

screen.getByRole('button', {name: /submit/i});

161

} catch (error) {

162

console.log('Available roles:');

163

logRoles(document.body);

164

throw error;

165

}

166

});

167

```

168

169

### Validating Accessibility

170

171

```javascript

172

import {getRoles, isInaccessible} from '@testing-library/dom';

173

174

test('navigation is accessible', () => {

175

const nav = document.querySelector('nav');

176

expect(isInaccessible(nav)).toBe(false);

177

178

const roles = getRoles(nav);

179

expect(roles.link).toBeDefined();

180

expect(roles.link.length).toBeGreaterThan(0);

181

});

182

```

183

184

### Comprehensive Accessibility Check

185

186

```javascript

187

import {getRoles, isInaccessible, logRoles} from '@testing-library/dom';

188

189

function validateAccessibility(container) {

190

console.log('=== Accessibility Report ===');

191

192

logRoles(container);

193

194

const allElements = container.querySelectorAll('*');

195

const inaccessibleCount = Array.from(allElements)

196

.filter(isInaccessible).length;

197

198

console.log(`

199

Total elements: ${allElements.length}

200

Inaccessible: ${inaccessibleCount}

201

Accessible: ${allElements.length - inaccessibleCount}

202

`);

203

204

const roles = getRoles(container);

205

const interactiveRoles = ['button', 'link', 'textbox', 'combobox'];

206

const interactiveCount = interactiveRoles.reduce((sum, role) => {

207

return sum + (roles[role]?.length || 0);

208

}, 0);

209

210

console.log(`Interactive elements: ${interactiveCount}`);

211

212

return {

213

totalElements: allElements.length,

214

inaccessibleCount,

215

interactiveCount,

216

roles: Object.keys(roles)

217

};

218

}

219

```

220

221