Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add refactored Combobox component #1559

Merged
merged 80 commits into from
Jun 22, 2023
Merged

feat: add refactored Combobox component #1559

merged 80 commits into from
Jun 22, 2023

Conversation

jzempel
Copy link
Member

@jzempel jzempel commented Jun 13, 2023

Description

Garden's current suite of combobox-like components – Autocomplete, Combobox, Multiselect and Select – is plagued with deep-seated accessibility issues, costly support maintenance, and APIs that challenging to navigate. This PR adds a new @zendeskgarden/dropdowns.next package with a fully refactored Combobox that is built to replace the existing component set with 100% WCAG 2.1 and WAI-ARIA 1.2 accessibility. The non-accessible component set will be removed in a future major release.

Detail

Key capabilities include:

  • Controllable: The Combobox functions in both uncontrolled and
    controlled
    modes. Controlled mode enables aspects, such as input value, selection value(s),
    listbox expansion, and current option active index, to share and adapt to the
    surrounding UI.
  • Autocomplete-able: Denotes the Combobox with list
    autocomplete
    . Filtering implementation is left to the API consumer.
  • Selectable: The Combobox API ensures the selection of one or more
    listbox option values, while also supporting the W3C no autocomplete
    example
    for use cases like search.
  • Multi-selectable: This feature enables the Combobox to provide WAI-ARIA
    multi-select listbox functionality with option-as-tag value rendering.
  • Non-editable: The Combobox supports select-only mode, where the user cannot modify the <input>.
  • Filterable: The Combobox offers various filtering methods for listbox
    options. Details of the filtering implementation are left to the API consumer.
  • Markup-able: The Combobox can convert input value text to rich HTML
    markup on blur in single-selection mode.
  • Decorate-able: The Combobox allows adding start and end media (SVG icons).
    Certain features will replace end media with Garden's standard dropdown chevron
    treatment.
  • Group-able: The Combobox API utilizes fully accessible <OptGroup>
    components for grouping, similar to the corresponding HTML element.
  • Compactible: Like other form elements, the Combobox supports compact
    sizing.
  • Field-able: The Combobox builds on Garden’s Field API context to
    establish accessible relationships with corresponding Label, Hint, and Message
    components.
  • Validate-able: The Combobox provides validation styling and
    accessibility comparable to other Garden form components.
  • RTL theme-able: Functionality displays and operates correctly for
    left-to-right and right-to-left layouts.

Checklist

  • 👌 design updates will be Garden Designer approved (add the designer as a reviewer)
  • 🌐 demo is up-to-date (yarn start)
  • ⬅️ renders as expected with reversed (RTL) direction
  • 🤘 renders as expected with Bedrock CSS (?bedrock)
  • 💂‍♂️ includes new unit tests. Maintain existing coverage (always >= 96%)
  • ♿ tested for WCAG 2.1 AA accessibility compliance
  • 📝 tested in Chrome, Firefox, Safari, and Edge

Copy link
Contributor

@Francois-Esquire Francois-Esquire left a comment

Choose a reason for hiding this comment

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

views often represent compositions of a user interface rather than a component (or its primitives). Views tend to be associated with application level thinking (like the MVC pattern) as well. What was the reason for src/views (instead of the conventional src/styled)?

@jzempel
Copy link
Member Author

jzempel commented Jun 20, 2023

What was the reason for src/views (instead of the conventional src/styled)?

@Francois-Esquire in light of future development plans, I want to establish a new/improved dev structure that more closely aligns with the documented API. In Garden, we historically refer to a "container-view-element" architecture. This structure reinforces that and takes weight off of the current choice of styled-components as a means for expressing view components.

Copy link
Contributor

@geotrev geotrev left a comment

Choose a reason for hiding this comment

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

No strong thoughts so far. The code looks solid. I'll take a look at the tests & storybook next.

@lucijanblagonic
Copy link

Here are a couple of things I noticed:

text-jump-on-focus
The text jumps on focus. It should stay in the same line.


image
Focus styling on Tags not up-to-date with updated outlines.


image
Validation Warning outline color doesn't match to updated focus outlines.


input-clear-after-escape
In this case I see that the Input clears text on the second Escape press. Do you think we should follow that behavior here?


Is there an enhancement opportunity where the keyboard can move the focus between tags with the arrow keys? In situations where you have multi-select + editable, it could be appropriate. 🤔

Copy link
Contributor

@Francois-Esquire Francois-Esquire left a comment

Choose a reason for hiding this comment

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

Solid work @jzempel 🙌 , left some feedback.

I noticed some visual tug-o-war between the scroll bar and the "Trigger" wrapping the input and tags. When multi-select is enabled with 2 or more tags and limited space, I'm seeing some overlap which may be undesirable:

Without focusInset:
with-tags

With focusInset:
with-focus-inset

const tagProps: Record<string, IOptionProps['tagProps']> = {};
const retVal = toOptions(children, tagProps);

setOptionTagProps(value => ({ ...value, ...tagProps }));
Copy link
Contributor

Choose a reason for hiding this comment

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

What was the reason for spreading the previous state?

A small concern I have about spreading the previous state is when it comes dynamic options, which is an edge case. It would result in persisting stale values and a possible memory leak.

Copy link
Member Author

Choose a reason for hiding this comment

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

Without this, tagProps get lost when options are filtered out – resulting in visual changes to currently selected tags. After careful consideration, I decided a "leak" wasn't a concern as the object will remain stable at N total options.

Copy link
Contributor

Choose a reason for hiding this comment

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

Well, what's the intended approach with virtual lists?

Copy link
Member Author

Choose a reason for hiding this comment

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

Virtualization (which isn't a recommended a11y approach here) doesn't change the situation. The state remains consistent at N total optionTagProps, where N = as many options that have tagProps as the user has experienced.

I'm thinking about putting a condition here to only set the state if the combobox isMultiselectable. Although, it would be silly for a consumer to add tagProps to a non-multiselectable combobox.

packages/dropdowns.next/src/index.ts Show resolved Hide resolved
packages/dropdowns.next/src/views/combobox/StyledHint.ts Outdated Show resolved Hide resolved
@jzempel
Copy link
Member Author

jzempel commented Jun 21, 2023

@lucijanblagonic thanks for the review. Here are replies to your comments above.

The text jumps on focus. It should stay in the same line.

I'm digging into this and will re-request your review when I have a solution committed.

Focus styling on Tags not up-to-date with updated outlines.

I hadn't merged in the latest main with updated tag styling - done now.

Validation Warning outline color doesn't match to updated focus outlines

Fixed in latest deploy.

I see that the Input clears text on the second Escape press. Do you think we should follow that behavior here?

I actually have this commented as a TODO in the underlying container 😉. We can explore this option as a follow-on. But, since the keyboard interaction is optional, I think the default should match what we currently have in Garden.

Is there an enhancement opportunity where the keyboard can move the focus between tags with the arrow keys?

I don't think so. This results in an accessibility violation with the current <Multiselect>. I do think there is an opportunity for design research that opens up improved possibilities for multiselectable tag keyboarding while staying true to a11y specs.

@jzempel
Copy link
Member Author

jzempel commented Jun 21, 2023

@Francois-Esquire re:

When multi-select is enabled with 2 or more tags and limited space, I'm seeing some overlap which may be undesirable

I'm not super concerned about this as the native scrollbar is better left alone – and isn't present by default (without enabling in system settings).

@jzempel
Copy link
Member Author

jzempel commented Jun 21, 2023

@lucijanblagonic the latest commit addresses...

The text jumps on focus. It should stay in the same line.

PR is ready for your re-review

Copy link

@lucijanblagonic lucijanblagonic left a comment

Choose a reason for hiding this comment

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

Everything looks good! 🙌

@jzempel jzempel merged commit 43d0410 into main Jun 22, 2023
1 check passed
@jzempel jzempel deleted the jzempel/combobox branch June 22, 2023 18:38
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Development

Successfully merging this pull request may close these issues.

6 participants