ARIA support ​
This section covers how to enable accessibility with UIExtension built-in features and related tooling. For ARIA specifications and best practices, see:
- https://www.w3.org/WAI/standards-guidelines/aria/
- https://www.w3.org/TR/wai-aria-practices-1.1/
- https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA
Enable accessibility in UIExtension ​
Load the aria add-on when initializing PDFUI:
javascript
new UIExtension.PDFUI({
addons: [
// .... other Add-on
'path/to/lib/uix-addons/aria/addon.info.json' // Make sure that aria is loaded last.
]
// ... other options
})If your app loads add-ons through allInOne.js, aria is already included—no separate load is required:
javascript
new UIExtension.PDFUI({
addons: 'path/to/lib/uix-addons/allInOne.js'
// ... other options
})For more on loading add-ons, see Add-ons overview.
Built-in UIExtension components ​
aria-label attribute ​
These built-in components add an aria-label attribute to the generated DOM when you set text or label. Click Run and test with a screen reader:
html
<html>
<template id="layout-template">
<webpdf>
<div>
<div>
<gtab text="XButton" group="aria-tab" body="tab1-body" active></gtab>
<gtab text="Dropdown" group="aria-tab" body="tab2-body"></gtab>
<gtab text="Slider" group="aria-tab" body="tab3-body"></gtab>
<gtab text="Ribbon button" group="aria-tab" body="tab4-body"></gtab>
</div>
<div name="tab1-body">
<xbutton text="button"></xbutton>
</div>
<div name="tab2-body">
<dropdown text="Dropdown" style="width: 8em" separate="false">
<xbutton text="Dropdown item 1"></xbutton>
<xbutton text="Dropdown item 2"></xbutton>
</dropdown>
</div>
<div name="tab3-body">
<slider min="0" max="100" step="1" label="Slider label"></slider>
</div>
<div name="tab4-body">
<ribbon-button text="Ribbon button"></ribbon-button>
</div>
</div>
<div class="fv__ui-body">
<viewer></viewer>
</div>
</webpdf>
</template>
</html>
<script>
var CustomAppearance = UIExtension.appearances.Appearance.extend({
getLayoutTemplate: function () {
return document.getElementById('layout-template');
},
disableAll: function () {
}
});
var libPath = window.top.location.origin + '/lib';
var pdfui = new UIExtension.PDFUI({
viewerOptions: {
libPath: libPath,
jr: {
licenseSN: licenseSN,
licenseKey: licenseKey
}
},
renderTo: document.body,
appearance: CustomAppearance,
addons: libPath + '/uix-addons/allInOne.js'
});
</script>json
{
"iframeOptions": {
"style": "height: 300px"
}
}Visually hidden content ​
Some content must be available to assistive technologies but hidden visually. Use the .fv__ui-aria-sr-only class—for example, to announce severity when color alone conveys meaning (danger, warning, and so on):
html
<p class="text-danger">
<span class="fv__ui-aria-sr-only">Danger:</span>
This action is not reversible.
</p>ARIA directives ​
@aria:attr directive ​
Sets attributes that start with aria-. Syntax: @aria:attr.${aria-property-name} where aria-property-name is listed on MDN. The value is an expression:
html
<html>
<template id="layout-template">
<webpdf>
<div @var.value="50">
<input @aria:attr.valuemax="1" @aria:attr.valuemin="0" @aria:attr.valuenow="value + '%'">
<!--Result:
<input aria-valuemax="1" aria-valuemin="0" aria-valuenow="50%" ...>
-->
<!-- source text -->
<input @aria:attr.label="'source text'">
<!--Result:
<input aria-label="source text" ...>
-->
<!-- I18n key -->
<input @aria:attr.label="'aria:labels.gotopage'|i18n">
<!--Result:
<input aria-label="Set page" ...>
-->
</div>
<div class="fv__ui-body">
<viewer></viewer>
</div>
</webpdf>
</template>
</html>
<script>
var CustomAppearance = UIExtension.appearances.Appearance.extend({
getLayoutTemplate: function () {
return document.getElementById('layout-template');
},
disableAll: function () {
}
});
var libPath = window.top.location.origin + '/lib';
var pdfui = new UIExtension.PDFUI({
viewerOptions: {
libPath: libPath,
jr: {
licenseSN: licenseSN,
licenseKey: licenseKey
}
},
renderTo: document.body,
appearance: CustomAppearance,
addons: libPath + '/uix-addons/allInOne.js'
});
</script>json
{
"iframeOptions": {
"style": "height: 300px"
}
}@aria:label directive ​
Sets the aria-label attribute. The directive value is an i18n key.
html
<html>
<template id="layout-template">
<webpdf>
<div>
<group-list>
<group>
<input @aria:label="aria:labels.gotopage"
placeholder="@aria:label="aria:labels.gotopage"">
<!--Result:
<input aria-label="Set page" ...>
-->
<!-- It is equivalent to: -->
<input @aria:attr.label="'aria:labels.gotopage'|i18n"
placeholder="@aria:attr.label="'aria:labels.gotopage'|i18n"">
<!--Result:
<input aria-label="Set page" ...>
-->
<!-- source text -->
<input @aria:label="source text" placeholder="@aria:label="source text"">
<!--Result:
<input aria-label="source text" ...>
-->
<!-- It is equivalent to: -->
<input @aria:attr.label="'source text'" placeholder="@aria:attr.label="'source text'"">
<!--Result:
<input aria-label="source text" ...>
-->
</group>
</group-list>
<group-list>
<group>
<!-- It can set attributes at a location specified by the dropdown component -->
<!-- Set aria-label on the drop-down arrow -->
<dropdown @aria:label.caret="Toggle Dropdown" text="@aria:label.caret"></dropdown>
</group>
<group>
<!-- Set aria-label on icons -->
<dropdown icon-class="fv__icon-toolbar-hand" @aria:label.icon="Click dropdown icon"
text="@aria:label.icon"></dropdown>
</group>
<group>
<!-- Set aria-label on the input box -->
<dropdown
editable
@aria:label.editor="Click dropdown icon"
selected="1"
text="@aria:label.editor"
>
<dropdown-item>Item 2</dropdown-item>
<dropdown-item>Item 3</dropdown-item>
<dropdown-item>Item 1</dropdown-item>
</dropdown>
</group>
<group>
<!-- Set the aria-label of the list -->
<dropdown @aria:label.list="Items" text="@aria:label.list" separate="false">
<dropdown-item>Item 1</dropdown-item>
<dropdown-item>Item 2</dropdown-item>
<dropdown-item>Item 3</dropdown-item>
</dropdown>
</group>
</group-list>
</div>
<div class="fv__ui-body">
<viewer></viewer>
</div>
</webpdf>
</template>
</html>
<script>
var CustomAppearance = UIExtension.appearances.Appearance.extend({
getLayoutTemplate: function () {
return document.getElementById('layout-template');
},
disableAll: function () {
}
});
var libPath = window.top.location.origin + '/lib';
var pdfui = new UIExtension.PDFUI({
viewerOptions: {
libPath: libPath,
jr: {
licenseSN: licenseSN,
licenseKey: licenseKey
}
},
renderTo: document.body,
appearance: CustomAppearance,
addons: libPath + '/uix-addons/allInOne.js'
});
</script>
<style>
input {
width: 20em;
}
.fv__ui-dropdown {
width: auto;
}
</style>json
{
"iframeOptions": {
"style": "height: 300px"
}
}@aria:labelledby directive ​
The @aria:labelledby directive generates aria-labelledby. Values use UIExtension selector syntax, not element id, because aria-labelledby references IDs and hand-written IDs can conflict globally. Selector syntax avoids that issue.
See aria-labelledby on MDN for details.
html
<html>
<template id="layout-template">
<webpdf>
<div>
<span>Field</span>
<!-- This is just for demonstration -->
<span name="a-colon">:</span>
<input type="text" @aria:labelledby="::parent()::childAt(0),a-colon">
</div>
<div class="fv__ui-body">
<viewer></viewer>
</div>
</webpdf>
</template>
</html>
<script>
var CustomAppearance = UIExtension.appearances.Appearance.extend({
getLayoutTemplate: function () {
return document.getElementById('layout-template');
},
disableAll: function () {
}
});
var libPath = window.top.location.origin + '/lib';
var pdfui = new UIExtension.PDFUI({
viewerOptions: {
libPath: libPath,
jr: {
licenseSN: licenseSN,
licenseKey: licenseKey
}
},
renderTo: document.body,
appearance: CustomAppearance,
addons: libPath + '/uix-addons/allInOne.js'
});
</script>
<style>
input {
width: 20em;
}
.fv__ui-dropdown {
width: auto;
}
</style>json
{
"iframeOptions": {
"style": "height: 300px"
}
}In this example, @aria:labelledby="::parent()::childAt(0),,a-colon" labels the <input> with the two preceding <span> elements. See component selectors for selector syntax.
@aria:describedby directive ​
@aria:describedby works like @aria:labelledby; see aria-describedby on MDN .
html
<html>
<template id="layout-template">
<webpdf>
<div>
<span>Field:</span>
<input type="text" @aria:labelledby="::parent()::childAt(0)"
@aria:describedby="::nextSiblings(),more-description">
<span class="fv__ui-aria-sr-only">
Description of text input.
</span>
<span class="fv__ui-aria-sr-only" name="more-description">
More description of text input.
</span>
</div>
<div class="fv__ui-body">
<viewer></viewer>
</div>
</webpdf>
</template>
</html>
<script>
var CustomAppearance = UIExtension.appearances.Appearance.extend({
getLayoutTemplate: function () {
return document.getElementById('layout-template');
},
disableAll: function () {
}
});
var libPath = window.top.location.origin + '/lib';
var pdfui = new UIExtension.PDFUI({
viewerOptions: {
libPath: libPath,
jr: {
licenseSN: licenseSN,
licenseKey: licenseKey
}
},
renderTo: document.body,
appearance: CustomAppearance,
addons: libPath + '/uix-addons/allInOne.js'
});
</script>
<style>
input {
width: 20em;
}
.fv__ui-dropdown {
width: auto;
}
</style>json
{
"iframeOptions": {
"style": "height: 300px"
}
}@aria:rel directive ​
Besides aria-labelledby and aria-describedby, ARIA defines many attributes that reference other elements. @aria:rel wraps the common ones:
aria-activedescendant:@aria:rel.activedescendant="selector,..."aria-flowto:@aria:rel.flowto="selector,..."aria-owns:@aria:rel.owns="selector,..."aria-controls:@aria:rel.controls="selector,..."
@aria:circular-focus directive ​
Controls focus cycling within a component—typically a dialog or isolated UI region.
Click Run to try the example below.
html
<html>
<template id="layout-template">
<webpdf>
<div>
<group-list>
<group>
<xbutton>button 1</xbutton>
<xbutton>button 2</xbutton>
<xbutton>button 3</xbutton>
</group>
<group @aria:circular-focus>
<xbutton @tooltip
tooltip-title="Press 'Shift + Tab' will switch focus to 'button 6' instead of 'button 3'">
button 4
</xbutton>
<xbutton>button 5</xbutton>
<xbutton @tooltip tooltip-title="Press 'Tab' will switch focus to 'button 4' instead of 'button 7'">
button 6
</xbutton>
</group>
<group>
<xbutton>button 7</xbutton>
</group>
</group-list>
</div>
<div class="fv__ui-body">
<viewer></viewer>
</div>
</webpdf>
</template>
</html>
<script>
var CustomAppearance = UIExtension.appearances.Appearance.extend({
getLayoutTemplate: function () {
return document.getElementById('layout-template');
},
disableAll: function () {
}
});
var libPath = window.top.location.origin + '/lib';
var pdfui = new UIExtension.PDFUI({
viewerOptions: {
libPath: libPath,
jr: {
licenseSN: licenseSN,
licenseKey: licenseKey
}
},
renderTo: document.body,
appearance: CustomAppearance,
addons: libPath + '/uix-addons/allInOne.js'
});
</script>
<style>
input {
width: 20em;
}
.fv__ui-dropdown {
width: auto;
}
</style>json
{
"iframeOptions": {
"style": "height: 300px"
}
}