WordPress.org

Making WordPress.org

Opened 3 years ago

Last modified 9 months ago

#2547 assigned defect

Review form; structure of star ratings

Reported by: anevins Owned by:
Milestone: Q1 Priority: normal
Component: Support Forums Keywords: needs-patch
Cc:

Description

The Review form provides the user a star rating option. I don't think the structure makes sense from the perspective of an assistive technology.

The current structure:

<div class="rate">
    <div class="wporg-ratings rating-stars">
        <a href="..." data-rating="1" title="Poor">
            <span class="dashicons dashicons-star-filled" style="color:#ffb900 !important;"></span>
        </a>
        <a href="..." data-rating="2" title="Works">
            <span class="dashicons dashicons-star-filled" style="color:#ffb900 !important;"></span>
        </a>
        <a href="..." data-rating="3" title="Good">
            <span class="dashicons dashicons-star-filled" style="color:#ffb900 !important;"></span>
        </a>
        <a href="..." data-rating="3" title="Good">
            <span class="dashicons dashicons-star-filled" style="color:#ffb900 !important;"></span>
        </a>
        <a href="..." data-rating="4" title="Great">
            <span class="dashicons dashicons-star-filled" style="color:#ffb900 !important;"></span>
        </a>
        <a href="..." data-rating="5" title="Fantastic!">
            <span class="dashicons dashicons-star-filled" style="color:#ffb900 !important;"></span>
        </a>
        <!-- hidden inputs -->
        <!-- script tags -->
    </div>
</div>


The current behaviour:

When hovering over the star icons, the icons are filled with a darker shade of yellow to indicate the to-be-selected rating. This is combined with a short explanation of the icon through the use of the 'title' attribute. For example, hovering over the 4th star will reveal the word "Great".

Issues with the current structure:

  • Anchor tags are used for the interactions. Anchor tags are meant to lead to content either on the same page or another page, they are not meant for custom interactions. These anchors will not be identified to assistive technologies as anything other than anchors and so this will be difficult to use.
  • The 'title' attribute isn't well supported by assistive technologies and is meant to supplement information already provided in text.
  • The ratings could be accidentally skipped because they are not form elements. Assistive technologies like screen readers have the option to use forms in a way that only navigates the form fields. This is to exclude unnecessary information on the page and focus on what's important for the task.
  • It relies on JavaScript. Although there are few people using the Web with JavaScript disabled, JavaScript can just fail to load for other reasons. In this case I don't think the form would operate correctly if JavaScript was disabled.

The solutions. I prefer Solution A.

Solution A:

  • Restructure the rating options to use form radio buttons.

Radio buttons are meant to be used in this scenario where there are multiple options that relate to one another and only 1 can be selected.

Suggested markup for Solution A:
HTML:

<fieldset class="rate">
    <legend>Your rating</legend>
    <label for="poor">
      <input id="poor" name="rating" type="radio"><span class="rate-item"><span class="rate-item-text">Poor</span></span>
    </label>
    <label for="works">
      <input id="works" name="rating" type="radio"><span class="rate-item"><span class="rate-item-text">Works</span></span>
    </label>
    <label for="good">
      <input id="good" name="rating" type="radio"><span class="rate-item"><span class="rate-item-text">Good</span></span>
    </label>
    <label for="great">
      <input id="great" name="rating" type="radio"><span class="rate-item"><span class="rate-item-text">Great</span></span>
    </label>
    <label for="fantastic">
      <input id="fantastic" name="rating" type="radio"><span class="rate-item"><span class="rate-item-text">Fantastic</span></span>
    </label>
</fieldset>

CSS:

/* Prevent focus styles appearing on hover */
body:hover input:focus + .rate-item {
    border-bottom: 0;
}

/* Remove margin on fieldset */
.rate {
    margin: 0;
}

/* To remove gaps between stars produced by inline-block */
.rate label {
    display: block;
    float: left;
}

/* Hide the rating input field */
.rate label input {
    left: -999em;
    position: absolute;
}

/* Hide the rating text */
.rate .rate-item-text {
    direction: ltr;
    display: block;
    overflow: hidden;
    text-indent: -999em;
}

/* Style the rating item ready to use before and after pseudo */
.rate .rate-item {
    display: block;
    position: relative;
    height: 20px;
    width: 20px;
}

/* Replicate the star font icon for star ratings */
.rate .rate-item:before {
    color: #ffb900;
    content: '\f154';
    display: block;
    font-family: dashicons;
    font-size: 20px;
    height: 100%;
    left: 0;
    line-height: 1;
    position: absolute;
    top: 0;
    width: 100%;
}

/* On focus & On hover: Change the star icon */
.rate input:focus + .rate-item:before,
.rate input:hover + .rate-item:before {
    content: '\f155';
}

/* On focus: Add an underline to the star for an additional visual cue */
.rate input:focus + .rate-item {
    border-bottom: 2px solid #ffb900;
}

That will achieve the same look and feel of the ratings, but it will still require some JS to accumulate the stars depending on what is selected. For example if "Great" is selected then 4 stars should be highlighted. The important thing is that JS will only enhance the experience. The form will still work with JS disabled.

I will write the JS later if we're going for this.

Solution B:

  • Make the link behave like a button by replicating the role and states of the button.

Suggested markup for Solution B:

<a href="#" aria-pressed="false" role="button">
  • The 'aria-pressed' attribute would have to be updated via scripting to reflect the state of the button.
  • You may have to compromise on showing the 'title' attribute, as the descriptions should be in the link text. The 'title' attribute can still be used, but it should add supplementary information.

Change History (6)

#1 @obenland
20 months ago

  • Keywords needs-patch added

@anevins I like approach A. Would you be willing to write a patch for it? I'd be happy to help you see it through!

#2 @anevins
20 months ago

@obenland, This CSS here will not work in IE8 & IE7:


/* On focus & On hover: Change the star icon */
.rate input:focus + .rate-item:before,
.rate input:hover + .rate-item:before {
    content: '\f155';
}

/* On focus: Add an underline to the star for an additional visual cue */
.rate input:focus + .rate-item {
    border-bottom: 2px solid #ffb900;
}

Would you still like to continue with this solution?

#3 @anevins
20 months ago

The JS (excuse the formatting in Trac).

var ratings = $('.rate'),
    // Define a class that we will add for a selected state
    selectedClass = 'js-rating-selected';

// If the ratings exist on the page
if (ratings.length !== 0) {
    // Get the input fields with the shared 'name' attribute with 'ratings' value
	var inputs = ratings.find('input[name="rating"]');

	// Watch those input fields for any state change, if the user selects one
    inputs.on('change', function(event) {
				// Get the current selected input
				var thisInput = $(event.target),
						previousInputs,
						nextInputs;

				
      // Get all the inputs before the current one
      previousInputs = thisInput
				.parent()
				.prevAll('label')
      	.find('input');
       
      // Get all the inputs after the current one
      nextInputs = thisInput
      	.nextAll('label')
				.find('input');

			// Reset the selected class
			inputs.removeClass(selectedClass);

      // Add a selected class to all the previous inputs
      previousInputs.addClass(selectedClass);
        
      // Remove the selected class to all next inputs
      nextInputs.removeClass(selectedClass);
    });
}

This ticket was mentioned in Slack in #forums by clorith. View the logs.


20 months ago

#5 @obenland
17 months ago

  • Owner set to obenland
  • Status changed from new to accepted

#6 @dd32
9 months ago

  • Milestone set to Q1
  • Owner obenland deleted
  • Status changed from accepted to assigned

Switching to radio buttons here seems like a great idea for assistive technology, lets try this out

Note: See TracTickets for help on using tickets.