What is accessibility and why is it important?
People with disabilities, like blindness or very poor vision need screen readers to be able to discern certain things on our banner. For example how many checkboxes it has, whether they're checked or not, or if the dialog is collapsed or expanded, etc.
They're things that a person with normal vision takes for granted and can simply see. Conversely they can't tell if any of the accessibility attributes are even there and won't miss them if they're absent.
For this very reason, accessibility is hard to get right (and we're still missing some attributes). There are tools available that can check if certain attributes are missing, but the only way to be really sure is from user feedback.
This script seeks to remedy the flaws we know are present today (March 1st 2021):
<script>
window.addEventListener("CookiebotOnDialogDisplay", function () {
var b = "DetailBodyContent",
c = "CybotCookiebotDialog",
d = document,
buttons = d.querySelectorAll("#" + c + "Body a"),
categories = d.getElementById(c + "BodyLevelButtonsSelectPane"),
details = [
d.getElementById(c + "BodyLevelDetailsButton"),
d.getElementById(c + "BodyButtonDetails"),
],
parent = categories.parentNode,
fieldset = d.createElement("fieldset"),
legend = d.createElement("legend"),
tabs = d.getElementById(c + b + "Tabs"),
tabpanel = document.getElementById(c + b + "CookieContainerTypeDetails")
.childNodes,
types = d.getElementById(c + b + "CookieContainerTypes");
function setActive(elem) {
var active = !1,
c = elem.childNodes;
for (var i = 0; i < c.length; i++) {
active = /Selected/g.test(c[i].getAttribute("class")) ? !0 : !1;
c[i].setAttribute("tabindex", active ? "0" : "-1");
c[i].setAttribute("aria-selected", active ? "true" : "false");
}
}
function addAccessibility(elem, a) {
var ariaControls = "CybotCookiebotDialogDetailBodyContent",
c = elem.childNodes;
ariaControls += a ? "" : "CookieContainerTypeDetails";
elem.setAttribute("role", "tablist");
a || elem.setAttribute("aria-orientation", "vertical");
for (var i = 0; i < c.length; i++) {
c[i].setAttribute("role", "tab");
c[i].setAttribute("aria-controls", ariaControls);
setActive(c[i].parentNode);
c[i].addEventListener("click", function () {
setActive(elem);
});
}
}
function setAriaExpanded(elem) {
elem.setAttribute("aria-expanded", "false");
elem.addEventListener("click", function () {
elem.setAttribute(
"aria-expanded",
elem.getAttribute("aria-expanded") == "false" ? "true" : "false"
);
});
}
d.getElementById("CookiebotDialogStyle").innerHTML +=
".CybotCookiebotDialogBodyButton:focus{outline:1px solid #007bc2;}";
legend.innerHTML = "";
legend.style.display = "none";
parent.insertBefore(fieldset, parent.firstChild);
fieldset.appendChild(legend);
fieldset.appendChild(categories);
d.getElementById(c + b).setAttribute("role", "tabpanel");
d.getElementById(c + "BodyLevelButtonsTable").style.display = "inline";
for (var i = 0; i < details.length; i++) setAriaExpanded(details[i]);
for (var i = 0; i < tabpanel.length; i++)
tabpanel[i].setAttribute("role", "tabpanel");
for (var i = 0; i < buttons.length; i++)
buttons[i].setAttribute("role", "button");
addAccessibility(tabs, !0);
addAccessibility(types, !1);
});
</script>
So what does it do?
If you have a look at our banner, there's actually quite a lot going on, without you realizing it:
First off, the 3 consent choice buttons and the details button aren't actually <button>
elements, they are <a>
elements (hyperlinks). So we have to tell a screen reader that they in fact function as buttons by assigning the role="button"
attribute.
The same can be said for tabs, these too are <a>
elements, and need to have role="tab"
attributes to signify that they function as tabs. The parent element which contains these tabs needs to be assigned the role="tablist"
attribute. The element which contains the tabs for the cookie categories needs to be assigned the aria-orientation="vertical"
attribute, to inform the user that these tabs are stacked vertically, and not horizontally which is the default.
The panel that goes with the tabs needs to be assigned the role="tabpanel"
attribute, and to signify the connection between the two the tab needs to be assigned the aria-controls
attribute, with the id of the tabpanel as its value.
For each of the tablists only one tab can have 0 as it's tabindex
value, the others must have -1, so pressing tab jumps to the next group of focusable elements, not the next element. To inform the user which tab is actively selected, the aria-selected
attribute needs to be used. The active tabs has "true" and the others have "false". These values need to be updated each time a different tab is selected.
When the details panel is opened, this needs to be signified with the aria-expanded
attribute, "false" for closed, "true" for opened.
The checkboxes need to be grouped, to signify they are related by encasing them in a <fieldset>
element. The Fieldset also needs to have a <legend>
element which essentially is used as a header. Currently this has no value, but it could be something like "Consent categories". The problem here, and the reason I've left this element empty, is that assigning this a value would deviate from the language the rest of the banner is displayed in, if this is anything other than English.
lastly, the checkboxes are displayed as "inline-table", which gives the impression data is contained within the table. To rectify this, I've assigned the element style = display: inline;
instead.
Essentially the script waits for the banner to announce that it's been loaded and is being displayed on the page, and then adds the attributes using DOM manipulation.
To add it to a page you can add the script inline, or copy the content in an external js-script and reference to that instead. Remeber to remove the <script>
and </script>
tags if you take the latter approach.
If you want to add the script using Google Tag Manager you can create a new Custom HTML tag. Copy the script above and paste it in the new tag.
Assign the "All pages" trigger and remember to publish your changes.
Comments
0 comments
Please sign in to leave a comment.