Skip to content

Conversation

mahoneycm
Copy link
Contributor

@mahoneycm mahoneycm commented Oct 22, 2024

Summary

Updated combo box result filtering. Now, search results are organized by results that start with the query, followed by results that contain the query.

Breaking change

This is not a breaking change.

Related issue

Closes #5647. Closes #5522.

Related pull requests

Change log PR →

Preview link

Combo box →

Time picker →

Problem statement

Combo box search results do not match user expectations. Keyboard and mouse users expect to see results that closely match their query.

Solution

By pushing results that start with their query closer to their top, we can more closely match user expectations.

Major changes

  • Combo box result organization has been updated
  • Time picker remains unaffected

Testing and review

  1. Visit combo box page
  2. Type in tan
  3. Confirm that results are sorted by options that start with your query first
  4. Confirm options containing your query are sorted after
  5. Make a selection
  6. Open the dropdown again
  7. Confirm that the selected option is still appearing in the correct order
  8. Backspace through the input and confirm dropdown updates
  9. Test with different queries or option lists (example provided below)
  10. Confirm no regression in time picker
  11. Confirm unit test passes

Testing checklist

  • Combo box behaviors match proposed solution
  • Results are ordered appropriately
  • Time picker is unaffected
  • Code is up to USWDS standards
  • Unit test matches expected pattern
  • Unit test passes

Additional information

I found testing with additonal select options beneficial during my work. Here's some example markup you can replace in usa-combo-box.twig to try the new behaviors with different results.

State select markup

<select class="usa-select" name="state" id="state">
  <option value>Select a state</option>
  <option value="AL">Alabama</option>
  <option value="AK">Alaska</option>
  <option value="AZ">Arizona</option>
  <option value="AR">Arkansas</option>
  <option value="CA">California</option>
  <option value="CO">Colorado</option>
  <option value="CT">Connecticut</option>
  <option value="DE">Delaware</option>
  <option value="DC">District Of Columbia</option>
  <option value="FL">Florida</option>
  <option value="GA">Georgia</option>
  <option value="HI">Hawaii</option>
  <option value="ID">Idaho</option>
  <option value="IL">Illinois</option>
  <option value="IN">Indiana</option>
  <option value="IA">Iowa</option>
  <option value="KS">Kansas</option>
  <option value="KY">Kentucky</option>
  <option value="LA">Louisiana</option>
  <option value="ME">Maine</option>
  <option value="MD">Maryland</option>
  <option value="MA">Massachusetts</option>
  <option value="MI">Michigan</option>
  <option value="MN">Minnesota</option>
  <option value="MS">Mississippi</option>
  <option value="MO">Missouri</option>
  <option value="MT">Montana</option>
  <option value="NE">Nebraska</option>
  <option value="NV">Nevada</option>
  <option value="NH">New Hampshire</option>
  <option value="NJ">New Jersey</option>
  <option value="NM">New Mexico</option>
  <option value="NY">New York</option>
  <option value="NC">North Carolina</option>
  <option value="ND">North Dakota</option>
  <option value="OH">Ohio</option>
  <option value="OK">Oklahoma</option>
  <option value="OR">Oregon</option>
  <option value="PA">Pennsylvania</option>
  <option value="RI">Rhode Island</option>
  <option value="SC">South Carolina</option>
  <option value="SD">South Dakota</option>
  <option value="TN">Tennessee</option>
  <option value="TX">Texas</option>
  <option value="UT">Utah</option>
  <option value="VT">Vermont</option>
  <option value="VA">Virginia</option>
  <option value="WA">Washington</option>
  <option value="WV">West Virginia</option>
  <option value="WI">Wisconsin</option>
  <option value="WY">Wyoming</option>
</select>

Copy link
Contributor Author

@mahoneycm mahoneycm left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Implementation notes:

Comment on lines +400 to +401
if (disableFiltering || isPristine) {
options.push(option);
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

note: adding isPristine here prevents selected values from appearing at the top of the combo box. This allows the selected item to appear in the correct order, which matches current combo box behavior

@mahoneycm mahoneycm marked this pull request as ready for review October 31, 2024 14:23
Copy link

@jaclinec jaclinec left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This works like a dream. I tested it by typing "Go" and it showed results starting with those letters first (i.e. Gooseberry) and a list of other options containing those letters (Dragonfruit, Mango, etc.). Looks great!

Copy link
Contributor

@amyleadem amyleadem left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is looking really good. I am still doing some edge case testing, but so far the results are returning as expected. A nice improvement!

In the meantime, I wanted to share some suggestions and questions to improve code readability. I'll cycle back with the results of the other review checks.

Copy link
Contributor

@amyleadem amyleadem left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Great work here @mahoneycm . Feels well-organized and well-scoped. Excited about this improvement.

Just have a few open comments about improving comments and naming for readability.

Testing

I completed the following checks using these queries:

Combo box: “Z”, “Ca”, “tan”, “go”, “orange”
Time picker: “1”, “12”, “12pm”

  • Confirm that combo box filters out options that do not match the query (pre-existing feature)
  • Confirm that time picker does not filter out options that do not match the query (pre-existing feature)
  • Confirm that the combo box sorts the filtered options by first showing content that “starts with” the query, and follows with results that "contain" the query
  • Confirm that combo box filters and sorts by the option text content, not the option value
    • Tested by adding a value of “hamburger” to an option with text content of "Apple". Querying “hamburger” did not return any results.
    • Confirm that this approach makes sense
  • Confirm that deleting a character from a selected values re-triggers the filter and sort
  • Confirm that upper- or lower-casing in the text content does not change the expected search results
  • Confirm code meets uswds standards
  • Confirm code has needed JSDoc comments
  • Confirm unit tests make sense and pass

Copy link
Contributor

@mejiaj mejiaj left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Overall the component functions much better, nice job!

Made comments to improve code quality and readability.

Additionally, I found a potential performance issue that we can split into another issue. Mainly because it's already happening in develop and level of effort might be beyond the scope of this issue.

Comment on lines 228 to 233
assert.ok(!list.hidden, "should display the option list");
assert.strictEqual(
list.children.length,
3,
"should filter the item by the string being present in the option",
);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

polish: The message could be misinterpreted.

Suggested change
assert.ok(!list.hidden, "should display the option list");
assert.strictEqual(
list.children.length,
3,
"should filter the item by the string being present in the option",
);
assert.ok(!list.hidden, "should display a filtered list based on input");
assert.strictEqual(
list.children.length,
3
);

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This was the test string used in each of the other filter tests so I reused for consistency. I updated this test description in e292603 but did not update the other test descriptions to reduce changed lines.

assert.strictEqual(
  list.children.length,
  3,
  "should display a filtered list based on input",
);

Let me know if you want me to go ahead update the other testing descriptions to follow the new pattern

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

praise: Thanks for updating and adding unit tests!

@mahoneycm mahoneycm requested a review from a team as a code owner November 8, 2024 14:57
@mahoneycm mahoneycm requested a review from amyleadem November 8, 2024 16:11
@mahoneycm
Copy link
Contributor Author

mahoneycm commented Nov 8, 2024

Update from dev sync

Using option.text to check for matches

After reviewing behaviors on develop I found that we were in fact already using the option.text attribute to check for matches.

As evident by this line:

regex.test(optionEl.text))

And the behavior in question from this work:

const optionMatchesQuery = (option) => regex.test(option.text);

This means there will be no additional changes in behavior for search results besides the intended option sorting.

Prevent list HTML rebuilding on every display

I was able to use a "cache" variable to store and compare results every time the list is displayed and prevent the HTML from being rebuilt on every display, however, there was an issue with our unit tests that caused 23 to fail as a result of this change.

Due to the scope of the issue, I think we should capture this work in another issue and accomplish as a fast follow up to this work.

I created #6193 to track this enhancement and #6195 to showcase a potential direction for the fix (note the related unit test failures in the CircleCI test)

Copy link
Contributor

@amyleadem amyleadem left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good to me! Both combo box and time picker are behaving as intended. All blocking comments have been addressed.

Overall, this feels like a nice, well-scoped change with some great readability improvements. Looking forward to seeing further improvements in #6193.

I've added a few comments with suggestions for improving the code comments, but don't think they need to block anything.

I've documented my tests in the section below:

Tests performed

  • Confirm that combo box filters out options that do not match the query (pre-existing feature)
  • Confirm that time picker does not filter out options that do not match the query (pre-existing feature)
  • Confirm that the combo box sorts the filtered options by first showing content that “starts with” the query, and follows with results that "contain" the query
  • Confirm the first item in the display list receives focus
  • Confirm that combo box filters and sorts by the option text content, not the option value
  • Confirm that deleting a character from a selected values re-triggers the filter and sort
  • Confirm that upper- or lower-casing in the text content does not change the expected search results
  • Confirm code is readable and organized
  • Confirm code has needed JSDoc comments
  • Confirm unit tests make sense and pass

Copy link
Contributor

@mejiaj mejiaj left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM, thanks for the updates. Unit tests pass and no regressions found.

Co-authored-by: Amy Leadem <93996430+amyleadem@users.noreply.github.com>
Copy link
Contributor

@annepetersen annepetersen left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM (all review items here work, but I only briefly reviewed the code)

@annepetersen annepetersen merged commit e87f19c into develop Nov 12, 2024
5 checks passed
@annepetersen annepetersen deleted the cm-combo-box-enhance-results branch November 12, 2024 16:09
@thisisdano thisisdano mentioned this pull request Nov 12, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Combo box search results do not match user expectations USWDS - Usability Testing: Combo box findings
5 participants