skip to Main Content

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.

  1. 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.

  2. I could wrap the whole element in the A tag and then do an event.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 that A tags should not wrap block elements (which a number of the elements in the card are). The second being that the event.stopPoropagation is a little smelly and could cause some unexpected behaviours down the track.

  3. I could take a hybrid approach and make the view link an A tag and apply an onClick event to the card div. I would then need to add the event.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


  1. 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.

    enter image description here

    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

    Login or Signup to reply.
  2. What if you use a layout like this?

    +-------------+
    |             |
    |    IMAGE    |
    |             |
    +-------------+
    |   HEADING   |
    +-------------+
    |     VIEW    |
    +-------------+
    |     SAVE    |
    +-------------+
    

    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…

    Login or Signup to reply.
  3. 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 CSS cursor: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:

    <div onclick="myclick()" style="cursor:pointer"> <!-- card container -->
      <img>
      <h2></h2>
      <a>view</a>
      <button>save</button>
    </div>
    

    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 or aria-labelledby. Personally, I would use aria-labelledby so that you can point to your heading as additional text for the link and the button. Something like this:

    <span id='viewtext' style="display:none">View</span>
    <span id='savetext' style="display:none">Save</span>
    
    <div onclick="myclick()" style="cursor:pointer"> <!-- first card -->
      <img>
      <h2 id='card1'></h2>
      <a aria-labelledby="viewtext card1" >view</a>
      <button aria-labelledby="savetext card1">save</button>
    </div>
    
    <div onclick="myclick()" style="cursor:pointer"> <!-- second card -->
      <img>
      <h2 id='card2'></h2>
      <a aria-labelledby="viewtext card2" >view</a>
      <button aria-labelledby="savetext card2">save</button>
    </div>
    

    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 in aria-labelledby.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search