I have a page that lists links to detail pages. These links are in the format of a card.
This card has an image, a heading, a view button and a save button.
+-----------------+
| |
| IMAGE |
| |
+-----------------+
| HEADING |
+-----------------+
| VIEW | SAVE | |
+-----------------+
Currently, the image, heading and view buttons are all A
tags that link off to a detail view of that item. The save button is a button
element that triggers a function in JS to save the list item. There is also some whitespace to the right of the save button that needs to be clickable and take the user to the detail page.
I have a recommendation from our SEO department to only have one element link. I see a couple of different ways to approach the problem but they all have downsides.
-
I could select just the view button to apply the link to as it holds the most valid semantic. However, this would cause a degradation in the user experience as they can no longer click anywhere on the card to proceed to the detail view.
-
I could wrap the whole element in the
A
tag and then do anevent.stopPropagation
on the save button (which we do not want to advance them to the detail page). This has a couple of problems. The first being thatA
tags should not wrap block elements (which a number of the elements in the card are). The second being that theevent.stopPoropagation
is a little smelly and could cause some unexpected behaviours down the track. -
I could take a hybrid approach and make the view link an
A
tag and apply an onClick event to the carddiv
. I would then need to add theevent.stopPropagation
to the save button.
I am not fully comfortable with any of these approaches but wanted to know if others have come across this and how they would solve it.
3
Answers
If the buttons are at absolute bottom like there is no space at the bottom of the card so I would do something like this.
Not sure if there is some space at the end of the card. Then this approach won’t work as the area under the button won’t be clickable
What if you use a layout like this?
You could wrap the image, the heading and the View button in the
a
link and leave out the Save button.I know it’s not really neat, but could be a workaround…
What was wrong with your option #3? Make the View an
<a>
and the Save a<button>
. For screen readers and keyboard-only users, they can tab to the View link or the Save button and perform their respective actions. Then add a click handler for the rest of the card to allow mouse users to click anywhere on the card. You’d probably want to set the CSScursor:pointer
for the click part of the card so mouse users have a visual clue as to where they can click.I would not set
tabindex="0"
on the clickable part of the card because the keyboard user does not need to get to that part of the card since they can already get to the View link.Perhaps something like this:
That should make the whole card clickable but since the
<button>
(and<a>
) are “on top” of the container, their handlers should run instead of the<div>
‘s click handler when they’re selected. But I didn’t test this to confirm.I know it’s invalid html to have a button nested in a link (
<a><button></a>
), and vice versa (<button><a></button>
), but I think you can nest a button/link in a clickable area.Keep in mind, though, that screen reader users can also display a dialog containing all the links or all the buttons on the page so you’ll want to have additional screen reader text associated with your ‘View’ and ‘Save’ elements. If you have multiple cards on the page, the screen reader dialogs will just show “View”, “Save”, “View”, “Save”, “View”, “Save”, etc and won’t be very helpful. They won’t know which card the View/Save belong too. You can provide additional screen reader text with
aria-label
oraria-labelledby
. Personally, I would usearia-labelledby
so that you can point to your heading as additional text for the link and the button. Something like this:I left out lots of details such as styling, the
href
for the anchor, etc, but hopefully you get the idea. Note that elements can be hidden and still referenced inaria-labelledby
.