Skip to content

Conversation

@jw-foss
Copy link
Contributor

@jw-foss jw-foss commented Jun 4, 2025

  • Fixes the issue that tab focus on the select trigger automatically opens the select dropdown.
  • Fixes the issue when selection occurred, the dropdown gets closed, the focus won't restore back to the trigger.

Summary

Root cause

As the screencast shows, when we tried to navigate via keyboards, the Tab key comes into play, whenever we Tab onto a select trigger, the dropdown automatically opens, and it does not attach focus state to the select items. According to the W3C standard https://www.w3.org/WAI/ARIA/apg/patterns/combobox/examples/combobox-select-only/ the Tab action should only set focus onto the trigger element (input in this case), with open keys such as space bar, enter, arrow down and arrow up (Home and End was not included in this PR), to open the popup, and sets focus on the selected item if any or first item in the selection list.

CleanShot.2025-06-04.at.14.01.26.mp4

Patch made

After this patch, the behavior should be aligned with the standard to allow user to set focus onto the trigger element, and they can use the open keys here to open the popup(dropdown), see the screenshot down below 👇

CleanShot.2025-06-04.at.13.36.31.mp4

/cc @portikM
KHCP-15521

* Fixes the issue that `tab` focus on the select trigger automatically opens the select dropdown.
* Fixes the issue when `selection` occurred, the dropdown gets closed, the focus won't restore back to the trigger.
@jw-foss jw-foss requested review from a team, Justineo, adamdehaven and jillztom as code owners June 4, 2025 06:15
@netlify
Copy link

netlify bot commented Jun 4, 2025

Deploy Preview for kongponents-sandbox ready!

Name Link
🔨 Latest commit 8b8c542
🔍 Latest deploy log https://app.netlify.com/projects/kongponents-sandbox/deploys/683feb9dce77220008775086
😎 Deploy Preview https://deploy-preview-2780--kongponents-sandbox.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.

To edit notification comments on pull requests, go to your Netlify project configuration.

@netlify
Copy link

netlify bot commented Jun 4, 2025

Deploy Preview for kongponents ready!

Name Link
🔨 Latest commit 8b8c542
🔍 Latest deploy log https://app.netlify.com/projects/kongponents/deploys/683feb9dd5f58d00089bcba6
😎 Deploy Preview https://deploy-preview-2780--kongponents.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.

To edit notification comments on pull requests, go to your Netlify project configuration.

@Justineo
Copy link
Member

Justineo commented Jun 4, 2025

I noticed that if I clicked outside the select menu to close it, the focus still returns to the select itself, is this intentional?

if (evt.keyCode === 27) {
if (evt.key === 'Escape' && isToggled.value) {
isToggled.value = false
popperRef.value?.hidePopover?.()
Copy link
Member

Choose a reason for hiding this comment

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

Shouldn't setting isToggled.value = false already closing the popper?

Copy link
Contributor Author

@jw-foss jw-foss Jun 4, 2025

Choose a reason for hiding this comment

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

Actually the isToggled does not control the state of popper this gets tricky when someone wants to mutate the state of the popper it's like we are controlling two states at the same time.

KToggle does not provide any control over KPopper, because the initial state of KToggle and KPopper were both false, it is our liability to sync the state.

if (key === 'Enter') {
e.stopPropagation()
e.stopImmediatePropagation()
}
Copy link
Member

Choose a reason for hiding this comment

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

What would happen if we didn’t stop here? Might be worth adding a comment.

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 should be dismissed, I only added this because previously we are using keyup on the trigger element KInput, and keydown on the SelectItem component. Removed.

@kongponents-bot
Copy link
Collaborator

Preview package from this PR in consuming application

In consuming application project install preview version of kongponents generated by this PR:

@kong/kongponents@pr-2780

@jw-foss
Copy link
Contributor Author

jw-foss commented Jun 4, 2025

I noticed that if I clicked outside the select menu to close it, the focus still returns to the select itself, is this intentional?

Looks like a bug, converting this to a draft for fixing minor issues.

@jw-foss jw-foss marked this pull request as draft June 4, 2025 09:10
Comment on lines +250 to +261
const focus = () => {
inputRef.value?.focus?.()
}

const blur = () => {
inputRef.value?.blur?.()
}

defineExpose({
focus,
blur,
})
Copy link
Member

Choose a reason for hiding this comment

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

suggestion: can we just expose the input ref rather than focus and blur methods?

Comment on lines +467 to +468
// TODO: when it is opened by 'Home', 'End', 'ArrowUp', 'ArrowDown' keys, it should handle
// setting focus to different item
Copy link
Member

Choose a reason for hiding this comment

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

I'm not sure I understand this comment.

}

if ((evt.key === 'ArrowDown' || evt.key === 'ArrowUp') && isToggled.value) {
// TODO: we need to remove this part since the popover should trap the focus
Copy link
Member

Choose a reason for hiding this comment

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

How do you then escape the popover?

Comment on lines +2 to +4
<div
ref="itemsContainer"
>
Copy link
Member

Choose a reason for hiding this comment

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

nit: this formatting change isn't necessary

const itemsContainerRef = useTemplateRef('itemsContainer')

const moveItemFocus = (direction: 'down' | 'up'): void => {
const moveItemFocus = (direction: 'down' | 'up' | 'current'): void => {
Copy link
Member

Choose a reason for hiding this comment

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

current being a value for a direction param is a bit confusing?

@jw-foss
Copy link
Contributor Author

jw-foss commented Jun 9, 2025

Hi @adamdehaven, thank you for reviewing my PR! Right now this PR has a few flaws, and I am trying to fix it before having a review 🙇

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.

5 participants