3

In HTML you can set your own shortcut keys in a form:

<label accesskey="n">name</label>

But, how would be the preferred form to display the "n" to make the user notice that this letter is the shortcut? The old convention is to display it underlined, which in HTML should be like this:

<label accesskey="n"><u>n</u>ame</label>

... but since <u> tags are discouraged in HTML5, is there a standard (or conventional) form to display this kind of shortcut characters in a HTML page?

P.S.: I know I can set a specific style through something like <span class="mystyle">n</span>, but I'm asking for an easier solution - preferrably some specific HTML tag.

Johannes
  • 64,305
  • 18
  • 73
  • 130
Little Santi
  • 8,563
  • 2
  • 18
  • 46

6 Answers6

4

One option is to use CSS to append the accesskey using CSS.

[accesskey]::after {
    content: " [" attr(accesskey) "]";
}
<label accesskey="n">name</label>

The only other option I can see (if you don't want to manually highlight the accesskey itself) is to use JavaScript to wrap the key.

// This uses ES6 syntax
// [].find() - https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/find
// NodeList.forEach() - https://developer.mozilla.org/en-US/docs/Web/API/NodeList/forEach
// ChildNode.replaceWith() - https://developer.mozilla.org/en-US/docs/Web/API/ChildNode/replaceWith

function parseHTML(htmlString) {
    return document.createRange().createContextualFragment(htmlString);
}

function findFirstTextNode(element) {

    return Array.prototype.find.call(element.childNodes, (node) => (
        node.nodeType === Node.TEXT_NODE
    ));
    
}

// Extremely basic implementation
function sprintf(string, ...args) {

    return args.reduce(
        (rendered, item) => rendered.replace("%s", item),
        string
    );

}

function highlightAccessKey(
    el,
    replaceString = "<span class=\"accesskey\">%s</span>",
    appendString = "<span class=\"accesskey\">[%s]</span>"
) {

    let accesskey = el.getAttribute("accesskey");
    let textNode = findFirstTextNode(el);

    if (textNode) {

        let text = textNode.textContent;
        let index = text.indexOf(accesskey);

        if (index > -1) {

            text = (
                text.slice(0, index)
                + sprintf(replaceString, accesskey)
                + text.slice(index + accesskey.length)
            );
            
        } else {
            text += sprintf(appendString, accesskey);
        }

        textNode.replaceWith(parseHTML(text));

    } else {
        el.appendChild(parseHTML(sprintf(appendString, accesskey)));
    }
    
}

document
    .querySelectorAll("[accesskey]")
    .forEach((el) => highlightAccessKey(el));
.accesskey {
    text-decoration: underline;
}
<label accesskey="n">name</label>

Sadly, there's not an out-of-the-box solution.

James Long
  • 4,629
  • 1
  • 20
  • 30
  • The CSS-based solution is the most approximate to my expectatives that I've read so far. Thanks! – Little Santi Jan 15 '18 at 16:31
  • Somewhat shorter version from 2022: https://jsfiddle.net/mplungjan/oka5v4w6/ – mplungjan Dec 13 '22 at 12:11
  • Can you explain a bit why `parseHTML` is needed? Doesn't the browser parse what JavaScript creates? See also https://stackoverflow.com/q/74808236/6607497 for a more complex challenge. – U. Windl Dec 15 '22 at 13:43
  • @U.Windl it's been a few years since I wrote this code and I haven't looked at it since, but it seems like `parseHTML` is designed to convert a string into DOM elements which can then be added to the page using `appendChild`. I believe that `appendChild` would fail if it were given a string and the newer method, `append`, would treat a string as text – James Long Dec 15 '22 at 13:46
2

You could use the title attribute to display the shortcut when the element is hovered:

<label accesskey="n" title="shortcut-key: n">name</label>
Johannes
  • 64,305
  • 18
  • 73
  • 130
  • 2
    Actually that is useless: The idea of accesskeys is that you use the *keyboard* to navigate. When you have to hover over the element using the mouse, you can also click, no need to go for the keyboard then! – U. Windl Dec 13 '22 at 10:38
2

Solution with little js

var sc = document.querySelectorAll('[accesskey]');
for (i = 0; i < sc.length; i++) sc[i].innerHTML = sc[i].innerHTML.replace(sc[i].accessKey, '<a>' + sc[i].accessKey + '</a>');
[accesskey]>a {
  text-decoration: underline;
}
<label accesskey="m">name</label>
Andrei Fedorov
  • 3,689
  • 2
  • 13
  • 25
  • Though I'd rather not to use javascript, this approach fixes with my requirements. Thanks! – Little Santi Jan 15 '18 at 16:42
  • I only wonder: How efficient is `document.querySelectorAll('[accesskey]')`? Would it be preferable to call a script with the ID of the element and the accesskey as parameters to add the accesskey and styling to the element? Also what would happen if you select `i` as accesskey in "Mississippi"? Would it only highlight the first occurrence, or all of them? – U. Windl Dec 13 '22 at 10:47
  • @U.Windl `document.querySelectorAll('[accesskey]')` include in all html elements with `accesskey` property. In context of the question this a good practice. Magic in the body of the cycle is up to you. You can use other js methods so that all `i` are marked. – Andrei Fedorov Dec 14 '22 at 04:22
1

Check it.

label[accesskey]>p::first-letter {
  text-decoration: underline;
}
<label accesskey="n"><p>name</p></label>
Andrei Fedorov
  • 3,689
  • 2
  • 13
  • 25
  • 3
    I thank for the effort, but the shortcut does not fall always in the first position. How would you make it for `` ? (BTW: I didn't downvote. I sincerely thank you for the answer). – Little Santi Jan 15 '18 at 16:05
  • @LittleSanti you wanted it to be easy. all other underline solutions are more difficult. – Andrei Fedorov Jan 15 '18 at 16:31
0

I put the letter with an Underline to show the shortcut on buttons or labels. There isn't a convention on HTML5 with the way to set it.

Also you can add the title attribute to show a little description with Shortcut Key.

Something like this:

<button type="button" onclick="alert('Hello world!')" title= "Shortcut: n" accesskey = "n">Click Me!</button>
0

Well, my own answer is to use <abbr> or <mark> (which are the most semantically approximated tags I've found for my purposes), in this mood:

With abbr

abbr {
  text-decoration: underline;
}
<p><label accesskey="n"><abbr>n</abbr>ame<input name="a1"/></label></p>

With mark

label mark {
  background-color: transparent; /* resets the bg color */
  text-decoration: underline;
}
<p><label accesskey="n"><mark>n</mark>ame<input name="a1"/></label></p>
Little Santi
  • 8,563
  • 2
  • 18
  • 46