Auto-Generating aria-label External Links using ColdFusion + Jsoup
Tags: coldfusion, jsoup, a11y, cfml
Published: 2020-09-20 23:09:44

While I don't claim any legal expertise in the ever-evolving <abbr title="Web Content Accessibility Guidelines">WCAG</abbr> requirements, some of our clients have received a "business alert" from an agency notifying them that "lawsuits are being filed regarding the Americans with Disabilities Act non-compliance of their websites". We've been using [WCAG 2.0 level AA](https://www.w3.org/WAI/WCAG2AA-Conformance.html), but some of the recent notices are claiming violations of 2.1 guidelines which aren't currently required by US government agencies or [Section 508.](https://www.section508.gov/) Apparently WCAG 2.1 may be currently required required by the European Union. The [EU's compliance deadline](https://wikis.ec.europa.eu/display/WEBGUIDE/01.+Accessibility+overview) for public sector websites is by Sep 23, 2020 (3 days from now), but my US clients aren't required to follow any EU mandates.

My business partner asked me if we could automatically generate `aria-label` attributes for `<a>` tags using the following rules:

## Aria-Label Generation Rules
1. Default = `aria-label="Link - opens in new window"`
2. If attr('title') exists, use it.
3. If text() is a plain text string, use the text.
4. If tag contains an `img` tag with an `alt` attribute, use the image's `alt` attribute.

We already perform many post-HTML generation optimizations using [ColdFusion](https://www.adobe.com/products/coldfusion-family.html) and [Jsoup](https://jsoup.org/). Some of the optimizations include:
- Jsoup auto-corrects invalid HTML. _(Valid HTML is critical for passing WCAG.)_
- Add CSP rules to the HTTP header
  - Inject `nonce` attribute to safe/allowed script hosts
  - Enforce `formaction=self` rule on dedicated login pages
  - Report violations to internally hosted [Taffy REST API](https://taffy.io/)
- Add `dns-prefetch` HTTP headers for all 3rd-party hosts
- Remove `console.log` for public visitors ([blog entry](https://dev.to/gamesover/sanitizing-console-log-from-html-using-coldfusion-regex-m3b))
- Rewrite shared resources paths to enable/disable CDN usage
- Auto-relocate inline CSS & JS scripts to `head` tag
- Relocate flagged JS scripts to bottom of `body` (like [GoogleAnalytics](https://analytics.google.com/analytics/) and [FontAwesome](https://fontawesome.com/))
- Generate unique `alt` attributes for missing `iframe` & `img` tags (another a11y requirement).

## Usage

Pass a string containing a whole or partial HTML fragment. Pass a suffix string (optional):

```js
// addAriaLabeltoHTML(HTML, suffix=" - opens in new window");
UpdatedHTML = addAriaLabeltoHTML(myHTML);
```

## Input/Output Unit Test Results

```html
<!-- <p>This is an <a href="/">HREF (default)</a> test.</p> -->
<p>This is an <a href="/">HREF (default)</a> test.</p> 

<!-- <p><a href="/" target="_self">HREF with '_self' target</a></p> -->
<p><a href="/" target="_self">HREF with '_self' target</a></p> 

<!-- <p><a href="/" target="_blank">anchor text test</a></p> -->
<p><a href="/" target="_blank" aria-label="anchor text test - opens in new window">anchor text test</a></p>

<!-- <p><a href="/" TARGET="_BLANK" title="My website">title test</a></p> -->
<p><a href="/" target="_BLANK" title="My website" aria-label="My website - opens in new window">title test</a></p> 

<!-- <p><a href="/" target="_blank" alt="HTML &amp; Entity">invalid alt + entity test</a></p> -->
<p><a href="/" target="_blank" alt="HTML &amp; Entity" aria-label="invalid alt + entity test - opens in new window">invalid alt + entity test</a></p> 

<!-- <p><a href="/" target="_blank">html <b>test</b></a></p>-->
<p><a href="/" target="_blank" aria-label="html test - opens in new window">html <b>test</b></a></p> 

<!-- <p><a href="/" target="_blank"><img src="test.gif" width="50" alt="Img alt test"></a></p> -->
<p><a href="/" target="_blank" aria-label="Img alt test - opens in new window"><img src="test.gif" width="50" alt="Img alt test"></a></p> 

<!-- <p><a href="/" target="_blank"><img src="test.gif" width="50" alt=""> IMG and text test</a></p> -->
<p><a href="/" target="_blank" aria-label="IMG and text test - opens in new window"><img src="test.gif" width="50" alt=""> IMG and text test</a></p> 

<!-- <p><a href="/" rel="nofollow noopener noreferrer external">rel: anchor text test</a></p> -->
<p><a href="/" rel="nofollow noopener noreferrer external" aria-label="rel: anchor text test - opens in new window">rel: anchor text test</a></p> 

<!-- <p><a href="/" rel="EXTERNAL" title="My website">rel: title test</a></p> -->
<p><a href="/" rel="EXTERNAL" title="My website" aria-label="My website - opens in new window">rel: title test</a></p>

```

## Source Code and CFML Demo

{% gist https://gist.github.com/JamoCA/24d0ad72aa1592060bd1b0c143c78599 %}