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

Trigger event after tooltip/popover is made visible, for ex for .focus() #661

Open
PVince81 opened this issue Mar 12, 2021 · 3 comments
Open

Comments

@PVince81
Copy link

Use case

We have create a popover menu component and would like to set the focus on the first element inside the popover right after it has appeared.

Problem

To be able to call .focus() on the first element, we need to make sure that at this moment the Popover is mounted in the DOM and it has the class .open set, as it has to be actually visible.

This is currently not possible to detect reliably as there is no event triggered at the right moment.
In our current implementation we had used $nextTick() but since Popover uses requestAnimationFrame, there is no guarantee how many milliseconds must elapse before the open class gets set here: https://github.com/Akryum/v-tooltip/blob/master/src/components/Popover.vue#L360

To test the problem have a component listen to then @open event of the Popover, and use the following handler:

		handleShow() {
			console.log('Popover: handleShow className=', document.querySelector('.popover')?.className)
			this.$nextTick(() => {
				console.log('Popover after nextTick: handleShow className=', document.querySelector('.popover')?.className)
			})
			window.setTimeout(() => {
				console.log('Popover after 1ms delay: handleShow className=', document.querySelector('.popover')?.className)
			}, 1)
			window.setTimeout(() => {
				console.log('Popover after 5ms delay: handleShow className=', document.querySelector('.popover')?.className)
			}, 5)
			window.setTimeout(() => {
				console.log('Popover after 20ms delay: handleShow className=', document.querySelector('.popover')?.className)
			}, 20)
			window.setTimeout(() => {
				console.log('Popover after 50ms delay: handleShow className=', document.querySelector('.popover')?.className)
			}, 50)
			window.setTimeout(() => {
				console.log('Popover after 100ms delay: handleShow className=', document.querySelector('.popover')?.className)
			}, 100)

You can see my result here:
image

The messages in-between is where I tried to re-try the focus after a delay after noticing that the focus was not actually set.
As you can see the $nextTick did not get access to the DOM element and the "open" class only starts to appear after 50ms or so.

Note: this only happens the first time the popover opens. The second time it will directly set this.isOpen=true here https://github.com/Akryum/v-tooltip/blob/master/src/components/Popover.vue#L343

Solution

Instead of having to add arbitrary delays, it would be nice to trigger the "show" event only once the popover is actually visible.
Or, if there are concerns with backwards compatibility, emit a new event "afterShow" there.

This way in our use case we could simply listen to that event and apply the focus there.

@PVince81
Copy link
Author

This was observed in v-tooltip version 2.0.3.

I didn't try master yet but saw that the logic is anyway the same there.

@PVince81
Copy link
Author

I just found that there's also an apply-show event, but still it would fire before the "requestAnimationFrame" initially: https://github.com/Akryum/v-tooltip/blob/master/src/components/Popover.vue#L443

@dword-design
Copy link

@PVince81 Setting no-auto-focus and @apply-show="$refs.input.focus()" fixes the issue for me. The lib seems to reset the focus somehow and no-auto-focus disables this.

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

No branches or pull requests

2 participants