How do I make links with no href attribute accessible? - javascript

A third party script is being used on a site I work on that replaces a few instances of <a href=""> with <a>. The links still work thanks to another part of the script, but they are no longer treated as links by user agents.
I can restore them to the tabbed navigation order by adding tabindex="0" but how can I make assistive technologies announce them as links or include them in a list of all links on a page?
Would adding role="link" help at all?
I am pushing the third party to improve their script so that the href is left intact. But in the meantime how do I best repair the damage that's being done?
I can't add either the original href or something like href="#" back to the links as the third party code will no longer do what it does. I hope that they improve their code so that I can, but for now I need to make the link accessible without the 'href'.

To make a non-href <a> behave like an <a> (and be accessible), you'd have to add role=link, tabindex=0, style it to look like a real link, and add keyboard handler code to treat Return as a click.
role="link" isn't sufficient; a screenreader may report it as a link, but without tabindex="0" and appropriate visual styles, a sighted user won't be able to tab to it in the first place, and without a keyboard event handler, only mouse users will be able to click it. (Technically screenreader users typically have hotkeys to simulate a mouse click, but keyboard-only sighted users generally don't have that option, so don't rely on it.)
Alternatively, if (big if!) the crazy script you're using allows for it, you could try shimming a 'keyboard click source' (my terminology) <a> just inside the original one: so where you have:
<a>foo</a>
you replace it with:
<a><a class='shim' href="javascript:void(0)">foo</a></a>
(The class='shim' is only needed if you need to do the event stuff described later...)
You can do this in jQuery using something like: (borrowing from Jack's answer)
$("a:not([href])").wrapInner("<a class='shim' href='javascript:void(0)'></a>")
How this works is that the inner newly-added <a ...> has a href, so it is exposed as a link and is tabbable. More importantly, if a user tabs to it and presses return, the default A behavior converts that keyboard input into a click event. This specific A has a href that returns undefined/void(0), so no actual navigation happens, but the click event will still bubble up to the original A, which gets to act on it.
(This is a neat pattern for allowing some parent element - often a DIV or similar - to handle click events, adding a child tabbable A that can source click events from keyboard gives you UI that's both mouse and keyboard usable.)
The big caveat here is that it assumes that your original script doesn't care about the target of the event. If that script does check this, it will get confused when it sees click events coming from the shim A's rather than the original As. One way to get around this is to capture and re-raise the event, which can be fiddly, and may only work on recent browsers - eg using something like:
// 'shim' class used so we can do this:
$("a.shim").click(function(e) {
e.preventDefault();
e.stopPropagation();
// the following works if listener using jQuery or is setting onclick directly, otherwise...
// $(e.target).parent().click();.
// More general way to raise events; may need alternate for IE<9
var e2 = document.createEvent("UIEvents");
e2.initUIEvent("click", true, true, window, 1);
e.target.parentNode.dispatchEvent(e2)
});

Whilst it's not very pretty, you can get at all anchors without a href attribute like so, using jQuery;
$("a:not([href])")
You can then just set the href attribute on those links to "#" and that should make them work again as regular links.
Here's a working JSFiddle
Sorry to reply with a jQuery solution...but doing this in regular JavaScript would be much more verbose.
Another way would be to give the anchors a role and then select them that way:
$("a[role='link']")

Related

jQuery/Javascript - how do you prevent the currently clicked item from losing focus when another element offpage is updated

Suppose you have a div that is at the very top (usually offscreen, due to a long page) that is updated with .append() when any of a bunch of links (scrolling also offpage) is clicked. How do you prevent Chrome from scrolling to the top automatically after each of the link clicks?
Something like this
<div id="updateme"></div>
<img>
...
[hundreds more]
There are several ways to solve this, and it is because you are using an anchor hashtag (#).
<img>
Instead, you could remove the href altogether but I am betting you want the style that href gives you. I would recommend using css to style the a to look and act like a link (which is probably the cleanest method), but you can also do this if you like:
<img>
This could also be covered with a little javascript when the page finishes loading as well if desired, since you listed jquery, it could be something like:
$('a[href="#"]').on('click', function(e) {
e.preventDefault();
});
If going the above route, just in case these are dynamically loaded in, you might want something like:
$('#updateme').on('click', 'a[href="#"]', function(e) {
e.preventDefault();
});
I strongly assume that Chrome doesn't scroll to the top because you are updating the content of the updateme element, but because your link points to #, which acts like an anchor on top of the page.
Personally I'm not a big fan of using href="#", because it makes it possible to middle-click or Ctrl+click the link, opening it in a new tab, which is not an intended functionality. I prefer using href="javascript:", but maybe there is an even better way that I don't know about.
If you want to leave the link as it is, to prevent Chrome from scrolling up when clicking the link, you have to make sure that only the click handler is run when you click the link, and Chrome doesn't actually navigate to the href you have specified, use onclick="event.preventDefault(); DoAppendUpdateMe()" (see preventDefault).

How can I stop the effects of the users clicks?

I am making a chrome extension to edit properties of images that are clicked on. I am using a package called element picker to select the images (this is triggered through an html button in a popup). The code works and I can change the properties of the image. However the package does not stop whatever action is linked to the image, which can often lead to the user being taken to a new page. How can I stop any of the actions of the users click between the time they press the button in the popup and they have selected an image?
Thank you in advance.
var elementPicker = require('element-picker')
function onClick(elt) {
[.....]
}
elementPicker.init({ onClick })
I don't usually recommend using this but CSS pointer-events can solve this problem. The idea is that any element with pointer-events:none will ignore any interactions. This works to block default HTML interactions like <a> or <button> as well as any javascript actions attached to the element.
This is the technique frequently used with a modal window to prevent clicks from going "through" the area around a modal. It should also work for what you described.
You could either set that style on the image element or on All Elements by using the * {styles...} selector. If you go the "all" route, you'll need to explicitly re-enable pointer-events on any elements in your extension interface that you still need actionable by using the 'auto' property.
Remember to reset pointer events when your extension is finished * {pointer-events: initial;} or you'll leave the page completely in-actionable.
If there is an Event object being passes through to the function then you could use the Event.preventDefault() function.
This function stops any default behavior and allows you to handle the event in your own manner.
Reference: https://developer.mozilla.org/en-US/docs/Web/API/Event/preventDefault

HTML: What is the point of using an anchor as a stub within an <a> element?

Is there an advantage to option 1 below? I see a lot of engineers using this but I've really strictly stuck to using <a> tags when I am directly linking and otherwise, I'd use a div.
1// <a href="#" onclick="doThis()>Foo</a>
2// <div onclick="doThis()>Foo</a>
<a></a> elements are commonly used for hyperlinks with a href attribute to indicate their destination.
In this case, the a tag acts like a button because you only want to trigger an event, not to link from one page to another. You’re trying to double up on watching when the user clicks. Because a standard click both activates the link and triggers the onclick event. I personally would use button tag in this case.
This is what I can think of
Advantages when using anchor
better keyboard (tab) navigation,
keyboard focus indicator
inbuilt browser appearance on hover, link, visited.
how screen readers read the tag and contents (mainly for accessibility)
As #Brenden and #Pointy mentioned a button would be sematically correct here as you dont have a href(but I think that you might be aware and question is about difference in approach ).
If you are using button and need the apperacne look like anchor you need to apply styles for :hover, :link, :visited etc.
Also if you are using <a href="#" onclick="doThis()>Foo</a> you need to prevent the default behavior of the anchor (eg: event.preventDefault()) else the page url will be be appended with # and page will be navigated to top.

What is meant by javascript:// in the href of a link

Yesterday, I visited a forum. There was like and Dislike button under the each post. When I click the Like button, the Like was counted without any page reload. Meaning Ajax was working, but when I check the href of that like link that was like this:
<img src="dbtech/thanks/images/likes.png" alt="Likes" title="Likes"> Like
I have also checked (using Visual Event) that there is no event listener attached to that link. So, I cant understand that how it works. Can some one explain?
javascript: return 0;
Does the same thing.
This would just uselessly create a random regular expression literal and then discard it. It is probably some programmer's ignorance.
This is included because an a tag has to have an href.
On its own, a link with href="javascript://" does nothing at all when clicked. This is as opposed to a link with href="#", which will set the anchor of the current location to #, or a blank or unset href, which will cause navigation to the current page.
In this case, since there's no explicit onclick handler and no event handler attached to this link, there must be some a event handler at a higher level that's catching click events as they bubble up to the page. Without being able to see the site, it's impossible to say for sure how it's working, but my guess would be that the data-button="likes" attribute is involved here.

Linking i DIV, handing over the "geturl" event to the browser

Ok, so this is a bit complicated. I have something like this code:
<div> Hello, I'm inside a DIV, please <a href='foo'>click here</a></div>
And I want to bind a click event to the DIV that follows the link of the contained A. No worries, this I can do all by myself, but the only method I know of is using "top.location", which bypasses the browsers normal handling of the link
In a nutshell, if I do it this way, if I hold my alt-key pressed when I click the DIV, the link won't open in a new tab, which is the behaviour in my browser.
Any ideas what so ever to handle this? I can't pre-code this new tab/new window behaviour since its user-configurable.
Try this:
$("a").trigger("click");
To open it in a new tab, you could set an attribute target="_blank" before triggering the event.
It isn't possible to trigger the browser's default handling of a link. The click() method (or jQuery equivalent) only runs the event handlers associated with a link; it does not follow the link, much less allow shift-click, middle-click, right-click-bookmark and so on.
To get the full behaviour of a link, you will need a real link. Wrap the contents of the following <div> in a new <a> with href pointing to the same place. Then if you need to, style the link so that it doesn't look like a link.

Categories