Skip to content

Instantly share code, notes, and snippets.

@viclafouch
Created December 18, 2020 10:52
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save viclafouch/acbcd48ad089faebc6c5d0cc92c1efcb to your computer and use it in GitHub Desktop.
Save viclafouch/acbcd48ad089faebc6c5d0cc92c1efcb to your computer and use it in GitHub Desktop.
An implementation of a Tooltip Component with React Hooks !
import React, { useCallback, useLayoutEffect, useRef, useState } from 'react'
import PropTypes from 'prop-types'
import usePortal from '@viclafouch/usePortal'
import { Styled } from './tooltip.styled'
import styled from 'styled-components'
const Styled = styled.div`
color: #ffffff;
padding: 4px 8px;
font-size: 1rem;
max-width: 300px;
word-wrap: break-word;
border-radius: 4px;
background-color: rgba(0, 0, 0, 0.5);
`
const Tooltip = ({
children, text, space, id
}) => {
const [style, setStyle] = useState(null)
const elementAttached = useRef()
const {
openPortal, closePortal, isOpen, Portal
} = usePortal()
const showTooltip = () => {
const css = {}
const dimensions = elementAttached.current.getBoundingClientRect()
let left = dimensions.left + dimensions.width / 2
left = Math.max(space, left)
css.left = Math.min(left, document.body.clientWidth - space)
css.bottom = window.innerHeight - dimensions.top + space
setStyle(css)
}
const hideTooltip = () => {
setStyle(null)
}
const handleEscap = useCallback((event) => {
if (event.keyCode === 27) {
setStyle(null)
}
}, [])
useLayoutEffect(() => {
if (style) {
openPortal((portal) => {
portal.current.setAttribute('role', 'tootlip')
portal.current.id = id
portal.current.style.cssText = `
position: absolute;
left: ${style.left}px;
bottom: ${style.bottom}px;
transform: translateX(-50%);
z-index: 1500;
`
})
document.addEventListener('keydown', handleEscap, false)
} else {
closePortal()
document.removeEventListener('keydown', handleEscap, false)
}
}, [style, openPortal, closePortal, id, handleEscap])
return (
<span
onMouseOver={showTooltip}
onMouseOut={hideTooltip}
onBlur={hideTooltip}
onFocus={showTooltip}
ref={elementAttached}
aria-describedby={id}
>
{children}
{isOpen && Portal(
<Styled>
{text}
</Styled>
)}
</span>
)
}
Tooltip.propTypes = {
children: PropTypes.oneOfType([
PropTypes.arrayOf(PropTypes.node),
PropTypes.node
]),
space: PropTypes.number,
text: PropTypes.string,
id: PropTypes.string
}
Tooltip.defaultProps = {
children: null,
space: 8,
text: '',
id: ''
}
export default Tooltip
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment