Tooltip, popover, dropdown, and menu library
MIT License
Bot releases are hidden (Show)
Published by atomiks over 5 years ago
animateFill
being broken, and onShown
/ onHidden
not being called (#427)<head>
when injecting CSSPublished by atomiks over 5 years ago
content
as a function (#424)Published by atomiks over 5 years ago
npm i tippy.js@latest
Overall minzipped size has been reduced by about 400 bytes
followCursor: 'initial'
works on touch devices tooscale
animation has its transform origin sticking to the reference elementtippy.hideAll()
method is now actually useful!It no longer checks hideOnClick
unexpectedly. In other words:
tippy.hideAll()
Does exactly what it says. All tippys will be hidden no matter what (using their own specified durations).
There's even options now too, for example, make all of them hide instantly (useful for scrolling):
tippy.hideAll({ duration: 0 })
Or exclude a particular instance from hiding:
tippy.hideAll({ exclude: tippyInstance })
tippy.group()
method - finally, a built-in solution to #81!How to use it:
const instances = tippy('button', { delay: 1000 })
tippy.group(instances)
// Optional:
tippy.group(instances, {
duration: number | [number, number], // instead of 0 between each show,
delay: number | [number, number], // if you didn't specify a delay in the instances
})
As simple as that, the tooltips will now instantly show when hovering between items in the group instead of waiting for the delay sluggishly.
updateDuration
option is now 0
instead of 200
by defaultFlips don't have the weird transition if using flipOnUpdate: true
(note that it's off by default now). Specifying a number now uses true smooth flips, where the popper element smoothly transitions from one placement to another. The effect is quite satisfying.
role
option - instead of tooltip
, certain popovers may need to be menu
or dialog
for accessibility reasons.tippy('button', {
role: 'menu'
})
<head>
, like the UMD version.// v3
import tippy from 'tippy.js'
import 'tippy.js/dist/tippy.css'
// v4
import tippy from 'tippy.js'
Also, files renamed to index
instead of tippy
.
In case you don't want this, you still can import it separately:
import tippy from 'tippy.js/esm'
import 'tippy.js/index.css'
Additionally, everything exists in the root directory instead of under dist/
. For example, themes:
import 'tippy.js/themes/light.css'
Why: cleaner import experience for consumers
popper.js
is external in all formats, so no more tippy.standalone
. This means CDN includes must reference it separately.<script src="https://unpkg.com/popper.js@1/dist/umd/popper.min.js"></script>
<script src="https://unpkg.com/tippy.js@4"></script>
<script>
tippy('button')
</script>
Why: to prevent popper.js
from becoming outdated and lagging behind popper releases, works like a dependency should
tippy.one()
. Instead, an instance will be returned in two cases: if the reference is either an element or a virtual element// v3
const collection = tippy('.btn')
const collection = tippy(document.querySelector('.btn'))
const instance = tippy.one('.btn')
const instance = tippy.one(document.querySelectorAll('.btn'))
// v4
// Instance
const instance = tippy(document.querySelector('.btn'))
const instance = tippy(virtualElement)
// Instance[]
const instances = tippy('#btn')
const instances = tippy('.btn')
const instances = tippy(document.querySelectorAll('.btn'))
Why: collections are not useful and don't need to exist. But we want to avoid an opaque return value if using a certain type. Therefore even if only a single element is given an instance when using a CSS selector, it always returns an array.
tippy.useCapture()
and tippy.disableAnimations()
Why: .useCapture()
is now default in v3 anyway. .disableAnimations()
was for testing environments however the new delay
value causes async behavior when hiding. In testing environments, use the following call to make everything synchronous:
tippy.setDefaults({ duration: 0, delay: 0 })
arrowTransform
optionWhy: Since introducing a bordered theme (light-border), using transforms distorts the shape of the arrow border. Arrow transforms should be specified in CSS using a theme.
autoFocus
and shouldPopperHideOnBlur
options. Remove all focus handling and leave it up to the developer.Why: The recommended accessible popover is to append it directly after the reference element which requires no focus handling. This will ensure focusable elements inside the tippy can be tabbed to afterwards. Sometimes this can be problematic though, with regards to z-index /stacking issues and the popover needs to be appended to the body. In this case it's up to the developer to create modal-like behavior with a close button and focus trapping, they can programmatically call .focus() where need be.
e.g. in the onShow()
lifecycle:
onShow(instance) {
const { tooltip } = instance.popperChildren
tooltip.style.transitionDuration = '0.2s'
tooltip.style.transitionProperty = 'visibility, opacity, height'
}
performance
to ignoreAttributes
Why: ignoreAttributes
describes what it's doing, performance
described the side effect of doing it
tippy.hideAllPoppers()
to tippy.hideAll()
Why: Shorter and more concise and conveys the same meaning
content
and appendTo
as functions receive the target element rather than the delegate referenceWhy: It's actually useful this way
livePlacement
to flipOnUpdate
, with much better behavior. It's now false
by default. The tippy will still update its position on scroll, but flipping while scrolling/resizing, etc is disabled by default.Why: Better UX (subjective) to keep the placement static after showing and prevent flips while scrolling
content
is an element, and you change elements inside it, you must call instance.popperInstance.scheduleUpdate()
.Why: MutationObserver
is not as robust as a ResizeObserver
and has been removed. If you want complete accuracy consider using a polyfill for ResizeObserver
.
Why: Let the developer have more control and not introduce unexpected styling
Fix for tippys with delays when leaving the popper, it sometimes would not close
Correctly parse null
in attributes
Published by atomiks over 5 years ago
npm i tippy.js@next
Overall minzipped size has been reduced by about 400 bytes
<head>
, like the UMD version.// v3
import tippy from 'tippy.js'
import 'tippy.js/dist/tippy.css'
// v4
import tippy from 'tippy.js'
Also, files renamed to index
instead of tippy
.
In case you don't want this, you still can import it separately:
import tippy from 'tippy.js/esm'
import 'tippy.js/index.css'
Additionally, everything exists in the root directory instead of under dist/
. For example, themes:
import 'tippy.js/themes/light.css'
Why: cleaner import experience for consumers
popper.js
is external in all formats, so no more tippy.standalone
. This means CDN includes must reference it separately.<script src="https://unpkg.com/popper.js@1/dist/umd/popper.min.js"></script>
<script src="https://unpkg.com/tippy.js@4"></script>
<script>
tippy('button')
</script>
Why: to prevent popper.js
from becoming outdated and lagging behind popper releases, works like a dependency should
tippy.one()
. Instead, an instance will be returned in two cases: if the reference is either an element or a virtual element// v3
const collection = tippy('.btn')
const collection = tippy(document.querySelector('.btn'))
const instance = tippy.one('.btn')
const instance = tippy.one(document.querySelectorAll('.btn'))
// v4
// Instance
const instance = tippy(document.querySelector('.btn'))
const instance = tippy(virtualElement)
// Instance[]
const instances = tippy('#btn')
const instances = tippy('.btn')
const instances = tippy(document.querySelectorAll('.btn'))
Why: collections are not useful and don't need to exist. But we want to avoid an opaque return value if using a certain type. Therefore even if only a single element is given an instance when using a CSS selector, it always returns an array.
tippy.useCapture()
and tippy.disableAnimations()
Why: .useCapture()
is now default in v3 anyway. .disableAnimations()
was for testing environments however the new delay
value causes async behavior when hiding. In testing environments, use the following call to make everything synchronous:
tippy.setDefaults({ duration: 0, delay: 0 })
arrowTransform
optionWhy: Since introducing a bordered theme (light-border), using transforms distorts the shape of the arrow border. Arrow transforms should be specified in CSS using a theme.
autoFocus
and shouldPopperHideOnBlur
options. Remove all focus handling and leave it up to the developer.Why: The recommended accessible popover is to append it directly after the reference element which requires no focus handling. This will ensure focusable elements inside the tippy can be tabbed to afterwards. Sometimes this can be problematic though, with regards to z-index /stacking issues and the popover needs to be appended to the body. In this case it's up to the developer to create modal-like behavior with a close button and focus trapping, they can programmatically call .focus() where need be.
performance
to ignoreAttributes
Why: ignoreAttributes
describes what it's doing, performance
described the side effect of doing it
tippy.hideAllPoppers()
to tippy.hideAll()
Why: Shorter and more concise and conveys the same meaning
content
and appendTo
as functions receive the target element rather than the delegate referenceWhy: It's actually useful this way
livePlacement
to flipScroll
, with much better behavior. It's now false
by default. The tippy will still update its position on scroll, but flipping while scrolling is disabled.Why: Better UX (subjective) to keep the placement static after showing and prevent flips while scrolling
content
is an element, and you change elements inside it, you must call instance.popperInstance.scheduleUpdate()
.Why: MutationObserver
is not as robust as a ResizeObserver
and has been removed. If you want complete accuracy consider using a polyfill for ResizeObserver
.
Why: Let the developer have more control and not introduce unexpected styling
followCursor: 'initial'
works on touch devices tooupdateDuration
option is now 0
instead of 200
by defaultFlips don't have the weird transition if using flipScroll: true
(note that it's off by default now). Specifying a number now uses true smooth flips, where the popper element smoothly transitions from one placement to another. The effect is quite satisfying.
scale
animation has its transform origin sticking to the reference elementtippy.hideAll()
method is now actually useful!It no longer checks hideOnClick
unexpectedly. In other words:
tippy.hideAll()
Does exactly what it says. All tippys will be hidden no matter what (using their own specified durations).
There's even options now too, for example, make all of them hide instantly (useful for scrolling):
tippy.hideAll({ duration: 0 })
Or exclude a particular instance from hiding:
tippy.hideAll({ exclude: tippyInstance })
tippy.group()
method - finally, a built-in solution to #81!How to use it:
const instances = tippy('button', { delay: 1000 })
tippy.group(instances)
// Optional:
tippy.group(instances, {
duration: number | [number, number], // instead of 0 between each show,
delay: number | [number, number], // if you didn't specify a delay in the instances
})
As simple as that, the tooltips will now instantly show when hovering between items in the group instead of waiting for the delay sluggishly.
role
option - instead of tooltip
, certain popovers may need to be menu
or dialog
for accessibility reasons.tippy('button', {
role: 'menu'
})
Published by atomiks almost 6 years ago
touchstart
passive for touchHold: true
listeners (#344)null
/ false
for the aria
option to disable the attribute completely (#402)inertia
animation a bitfollowCursor: 'initial'
edge case fix with delaysPublished by atomiks almost 6 years ago
followCursor: 'initial'
option (#374)boundary
option (#394)autoFocus
and aria
options (#393)Published by atomiks almost 6 years ago
popper.js^1.14.6
includes position rounding fixesanimateFill: true
google
theme adheres to size
optionlight-border.css
due to Popper.js issuePublished by atomiks almost 6 years ago
tippy.useCapture()
and make capture phase for the global click listener default. This prevents the need to wrap calls to .show()
in setTimeout
if manually triggering the tooltip after a click event somewherecharacterData
to the popper mutation observer so changes to textual content within a tippy is detected and its position updated accordingly. Mainly noticeable in React updates.state.isMounted
over state.isVisible
to determine if hide(0)
should be called when destroying a tippy. This was not a leak but caused glitches when using the React component after changing routes and unmounting the Tippy component.Published by atomiks almost 6 years ago
Published by atomiks almost 6 years ago
data-tippy-content
attribute (#341)Published by atomiks almost 6 years ago
Published by atomiks about 6 years ago
It's now on npm as the default @latest
.
npm i tippy.js
View the docs: https://atomiks.github.io/tippyjs/
This version changes the API on a fundamental level, so you will need to update all your call sites. You no longer use a title
attribute, and there is no longer an html
option. Instead, both of them have been streamlined into a single option called content
.
In addition, tooltips can now be auto-initialized.
<button data-tippy="Tooltip">Text</button>
<button data-tippy="<strong>HTML</strong>">Text</button>
Elements with a data-tippy
attribute are automatically given a tooltip. You no longer need to touch JavaScript. (Note on performance: It takes <1ms to do this check on a page if there are no tooltips).
You can give elements a data-tippy-content
attribute and use the function:
<button data-tippy-content="Tooltip">Text</button>
<script>tippy('button')</script>
Or specify the content as an option:
<button>Text</button>
<script>tippy('button', { content: 'Tooltip' })</script>
It can contain HTML, and you can use an HTMLElement
as the value.
The object that is returned:
selector
is now named targets
tooltips
is now named instances
popperChildren
: access the children of the popper element easily without needing to do query selections or manual DOM walking.options
has been renamed to props
. Options are the props you supply optionally to tippy(), but it doesn't make sense for the tooltip configuration object to be called options.state
object properties are all prefixed with is
because they are boolean values.listeners
made privatemultiple: Boolean
can the tooltip have multiple tippy instances?createPopperInstanceOnInit
is now lazy: Boolean
with the reverse behavior.maxWidth
removed - should be handled via a themehideOnClick
changes "persistent"
to "toggle"
and it has the opposite behavior. This means that hideOnClick: false
will prevent click-triggered tooltips from ever hiding unless you specify "toggle"
import
ing tippy.tippy.set(options)
This was previously impossible with v2: you can now change any option at runtime after the tippy instance was created.
tippy.setContent(newContent)
Shortcut for .set({ content: newContent })
followCursor: Boolean|"horizontal"|"vertical"
You can now make the tooltip follow the cursor on a single axis instead of both by specifying a string.
touch: Boolean
An option to effortlessly disable a tooltip from displaying on touch devices.
a11y: Boolean
An option to ensure the reference element can receive focus.
showOnInit: Boolean
Show the tooltip immediately?
onShow
/ onHide
You can now cancel lifecycles by returning the boolean false
.
shouldPopperHideOnBlur: Function
Added due to improved focus handling
interactiveDebounce: Number (ms)
Debounce on the internal onMouseMove
handler for interactive inline text tooltips that span 2+ lines
#193
#139
Accessibility/focus handling
Focus handling and accessibility has been improved. Tabbing/keyboard nav around interactive tooltips now works better.
A lightweight wrapper is now officially published under @tippy.js
org.
npm i @tippy.js/react
View the docs for the React component here
I hope you like it! 🎉
Published by atomiks about 6 years ago
tippy.useCapture()
method to change the global click listener to use capture before bubbling. Call it before any calls to tippy()
onTransitionEnd
does not fire with onHidden
by removing an internal hack, and using delay: [0, 20]
as the default instead of delay: 0
Published by atomiks about 6 years ago
"module"
field points to the dist/esm/tippy.standalone.js
file for latest 1.x Popper.js dependencyshouldPopperHideOnBlur
option, closes #285role
attribute from popper elementPublished by atomiks about 6 years ago
set()
if content was not changed.20ms
and remove onHidden transitionend hack.Published by atomiks about 6 years ago
interactiveDebounce
(number in ms) option (#274)tippy.hideAllPoppers
static method exposedset()
method which now integrates better with React, etc.Published by atomiks about 6 years ago
popperOptions
not being usedtippy.defaults
not updating when using tippy.setDefaults()
.setContent()
method as a shortcut to .set({ content })
autoInit()
function is deferred with setTimeout()
to allow the defaults to be changed before auto-initializationPublished by atomiks about 6 years ago
scale
and perspective
esm
directory and module
field in package.jsonPublished by atomiks over 6 years ago
The first alpha release of Tippy.js v3.
npm i tippy.js@next
You no longer use a title
attribute on elements, and the html
option has been removed. Both functionalities have been streamlined into a single prop: content
.
<button data-tippy="Tooltip">Text</button>
<button data-tippy="<strong>HTML</strong>">Text</button>
Elements with a data-tippy
attribute are automatically given a tooltip. You no longer need to touch JavaScript. (Note on performance: It takes <0.5ms to do this check on a page if there are no tooltips).
content
You can give elements a data-tippy-content
attribute and use the function:
<button data-tippy-content="Tooltip">Text</button>
<script>tippy('button')</script>
Or specify the content as an option.
<button>Text</button>
<script>tippy('button', { content: 'Tooltip' })</script>
It can contain HTML, and you can use an HTMLElement
as the value.
tippy()
callThe object that is returned:
selector
is now named targets
tooltips
is now named instances
popperChildren
property: access the children of the popper element easily without needing to do query selections or manual DOM walking.options
has been renamed to props
. Options are the props you supply optionally to tippy()
, but it doesn't make sense for the tooltip configuration object to be called options
. Instead, it's now props
, inspired by React.state
object properties are all prefixed with is
because they are boolean values.listeners
made privateThe most useful new method is set()
. It allows you to update the props of a tooltip after it has been created.
const tip = tippy.one('.btn', {
content: 'Hello!',
arrow: true,
delay: 500
})
// Later on...
tip.set({
content: 'Bye!',
arrow: false,
delay: 0
})
tippy.setDefaults(props)
- pass an object in to change the default configurationtippy.browser
removeda11y: true
- (accessibility shorthand): ensure the reference element can receive focusallowTitleHTML: true
is now allowHTML
hideOnClick
changes "persistent"
to "toggle"
and it has the opposite behavior. This means that hideOnClick: false
will prevent click
-triggered tooltips from ever hiding unless you specify "toggle"
. Not 100% sure on this, however.touch: true
- display the tooltip on touch devices?createPopperInstanceOnInit: false
is now lazy: true
. More concise name.showOnInit: false
- show the tooltip immediately?maxWidth
removed. Should be handled by a theme in CSS because of narrow mobile devices.multiple: false
- can the reference have multiple tippys? Currently each new instance overrides the previous _tippy
property. It most likely needs to be turned into an array on the second init, but I fear this causes unpredictable behavior. (The previous option which allowed multiple click triggered tooltips to be open is now gone. I don't see much demand for it, but it might return as a different name).duration/delay
: you can now leave a value undefined in the array and the default value is used. e.g. duration: [, 100]
(use default for show) or duration: [100]
(use default for hide). It's more concise than an object: duration: { hide: 100 }
but the syntax is kind of messy. Might change this.Focus handling and accessibility has been improved. Tabbing/keyboard nav around interactive tooltips now works better.
I believe this should be handled by the user, not the library.
The best way is to inline the tooltip content next to the reference element on old mobile & desktop browsers for interactive HTML popovers. For simple tooltips on desktop, manually set the title
property on the element.
Unsupported = <0.5% worldwide usage or nonstandard browsers.
theme
but requires lots of boilerplate selectors. Would be nice to make it declarative as an option.Published by atomiks over 6 years ago