WCAG Compliance, patching standard UI5 controls without using extensions
Accessibility, WCAG, UI5….
If you’re reading this blog, you probably already know the painful reality that a lot of the standard controls in SAPUI5 are not very accessible, by no fault of your own, they simply do not render accessible html in some cases. As of the time of writing this, the latest version 1.73.1 has brought many much needed and welcome improvements to accessibility, but there’s still some lingering issues that we have no choice but to address ourselves for the time being.
In the past, I’ve used and advocated control extensions to fix WCAG issues (using the onAfterRendering function to make DOM corrections). This means you just swap out any given control with your own wrapped version. But this itself becomes very tedious to implement in all your views.
Recently, Bradley and myself pondered whether we could achieve the same sort of patching of controls, but without the use of extensions, so that nothing needed to be changed in an existing app to bring up its compliance level. We wanted WCAG patches to be applied to an app with a single line of code, and well… we achieved that goal!
We’ve developed a small wcagHelper library, that when loaded, automatically detects and patches each control in your app as they’re instantiated. So for example you can just use a standard sap.m.CheckBox in your views and the library will automatically append additional onAfterRendering logic to it to correct its aria tags. It does this by monitoring changes to the DOM, and tracing those elements back to UI5 controls.
In this blog I’ll be using the WAVE tool for chrome for WCAG testing (you should also use aXe). At the time of writing this we have only implemented a handful of WCAG fixes, but the pattern is simple, so you should have no trouble adding any and all corrections that you may need. We also found that a lot of our past corrections are no longer required in the latest version 1.73.1 so thankfully there’s A LOT of code we didn’t need to port over to this library from our previous projects.
So here’s some very simple UI5 XML, in version 1.73.1, as an example of a few aria tagging faults.
It renders like so…
Which appears to be fine visually, but when we run a tool such as WAVE for chrome, we can see a few issues.
Each of those orange and red icons are warnings and errors, most of these are issues with aria tags, for accessibility tools to work correctly they need to know which labels are associated with which input controls. By default these are not being placed correctly in the DOM. in the case of the select control a label element is being used to show content when a span is appropriate for that case.
So as previously mentioned, I would normally fix these issues by writing control extensions, and using those extensions instead of the default controls. But with the wcagHelper library, I instead, only need to load the library, and it will patch the controls as needed.
I do this in the component.js of my application. Note that your path (second parameter) may be different, depending on where you’ve placed the wcagHelper folder in your environment. But the proper use of libraries in UI5 is a whole separate topic.
As you can see, I even put this above my component definition itself, it’s the first thing that’s done. Technically it can go anywhere, but I like it to be right at the top so I can clearly see my dependencies.
Now that our library is loaded, I can run WAVE again, and see the improvements (NOTE: Nothing else has changed, the xml view remains unchanged)
Well well well, would you look at that. the errors and warnings are gone and everything appears to be labelled correctly. (the green icons of wave represent correct label tagging)
So now, patching for WCAG issues, is as simple as importing the library, and any additional improvements we make to the library along the way, will automatically apply to every view in every app that is using it!
The only way this could be better is if it just worked out-of-the-box 😉
We can also confirm that the library is working, by checking the browser console, where each control type will be mentioned like so
How it works
So I guess I should explain a little bit more, how the library achieves this.
The project structure looks like this…
The manifest.json and library.js are pretty standard looking library definitions. The other js files, are all global objects, most important is the UIMonitor.js, which listens for changes to the DOM, it is with this technique that we avoid having to make any changes to the views, as we can simply detect each control as it’s instantiated.
NOTE: Internet Explorer 9 and lower, will not execute the DOMNodeInserted event correctly, so if you absolutely need to support those “browsers” then I have bad news for you…
As you can see from the above, once a new control is detected, the patchControl function is called for it, which will find and apply the appropriate patches for that control type, which is where the files within the ControlPatches folder come into play. Each of these contain an onAfterRendering function, which will be attached to the control. For a patch class to be used, it needs to be listed I nthe UICatalog.js file.
Lets take a look at the select control for example
We can see that we have an entry in our UICatalog for sap.m.Select
Because there is an entry for this control, the ControlPatches/Select.js file will be loaded, which contains an onAfterRendering function
This onAfterRendering function, will be attached to every sap.m.Select control, so that during the render lifecycle, this code will run. In the case of our select control we are doing a simple element replacement, switching out the label element for a span element. The fixes here can be anything you need, just be sure to always use this.$() object when making DOM adjustments, to ensure you are only modifying within the context of the current control (this is no different to how you would do it within a control extension)
And that’s basically it, any control that needs a patch, gets a patcher class and an entry in the catalog, and that’s it!
Download & Contribute
You can find the full source of community.wcagHelper on GitHub:
Hopefully by the time you’re reading this there’s even more patches available. If there’s more simple DOM changes that you know of, that should be applied, then I encourage you to not only add them in for yourself, but to submit them to the GitHub live copy for the wider community, accessibility is a community problem, but as a community, we can solve it.
Bradley co-developed this library with me, he has some great blogs on Hana development, which you should definitely check out. He also wrote a chrome extension for detecting deprecated UI5 controls, very useful during landscape upgrades.