Empresas
Empregos
  • Sobre nós
  • Soluções
    • Publicação de vagas
      Publique sua vaga e receba candidatos qualificados em 48h.
    • Avaliações de candidatos
      Mais de 500 testes técnicos e psicológicos, mais anti-fraude.
    • Headhunting
      Busca executiva personalizada do início ao fim.
    • Folha de Pagamento + EOR
      Dispersão de folha e EOR em mais de 15 países da LATAM.
  • Preços
  • Empregos

0

144
Visualizações
How to create a basic Tooltip in React where you don't actually wrap the anchor element in another DOM element?

Most of the APIs for Tooltips in React I've seen work something like this:

<Tooltip title="Hello World">
  <span>hover me!</span>
</Tooltip>

What that ends up creating is a wrapper around that span, something like this:

<div>
  <span>hover me!</span>
</div>

On that div, now, you can add your mouseenter/leave handlers and such, and figure out the rest of the tooltip implementation. I am not concerned with all the other features for implementing a robust React tooltip, but more wondering how from a technical perspective you go about wrapping that <span>, but without adding the extra <div>, I can't see how it can be done in React land (ideally with something like Portals).

If I use React.cloneElement(child, { mouseenter: .... }) you run the risk of overriding the child's mouse handlers, but that is one possible way to do it. (I don't know how to basically do super here, get the passed in mouse handlers, and then wrap them with my own tooltip mouse handler, if they are present, any ideas?).

How would you go about implementing simply the binding part of a tooltip component, where it adds the handlers to the passed in child, using the above sort of API? Maybe you could also cloneElement and add a custom ref or something, but same override problem exists there and not sure how to work around that. Any help would be appreciated. To learn more React technical details, I would like to play around with making a basic tooltip, and see how you should approach this problem in React-land.

about 4 years ago · Juan Pablo Isaza
1 Respostas
Responde à pergunta

0

I figured it out:

import ReactDOM from 'react-dom'
import React, { useState, useCallback, useEffect } from 'react'

export default function Tooltip({
  content,
  mouseEnterDelay = 200,
  mouseLeaveDelay = 500,
  children,
}) {
  const [portalContainer, setPortalContainer] = useState(typeof document !== 'undefined' && document.querySelector('#tooltip'))
  const [mouseEnterDelayTimer, setMouseEnterDelayTimer] = useState(null)
  const [mouseLeaveDelayTimer, setMouseLeaveDelayTimer] = useState(null)
  const [isVisible, setIsVisible] = useState(false)

  const child = children

  const oldMouseEnterHandler = child.props.onMouseEnter
  const oldMouseLeaveHandler = child.props.onMouseLeave

  const clearMouseLeaveTimer = useCallback(() => {
    clearTimeout(mouseLeaveDelayTimer)
    setMouseLeaveDelayTimer(null)
  }, [mouseLeaveDelayTimer, setMouseLeaveDelayTimer])

  const clearMouseEnterTimer = useCallback(() => {
    clearTimeout(mouseEnterDelayTimer)
    setMouseEnterDelayTimer(null)
  }, [mouseEnterDelayTimer, setMouseEnterDelayTimer])

  const show = useCallback(() => {
    clearMouseEnterTimer()
    setIsVisible(true)
  }, [setIsVisible, clearMouseEnterTimer])

  const hide = useCallback(() => {
    clearMouseLeaveTimer()
    setIsVisible(false)
  }, [setIsVisible, clearMouseLeaveTimer])

  const handleMouseEnter = useCallback((e) => {
    oldMouseEnterHandler?.(e)
    console.log('handleMouseEnter', mouseLeaveDelayTimer)

    if (mouseLeaveDelayTimer) {
      clearMouseLeaveTimer()
      return
    }

    const timer = setTimeout(show, mouseEnterDelay)
    setMouseEnterDelayTimer(timer)
  }, [clearMouseLeaveTimer, oldMouseEnterHandler, setMouseEnterDelayTimer, show, mouseEnterDelay, mouseLeaveDelayTimer])

  const handleMouseLeave = useCallback((e) => {
    console.log('handleMouseLeave', mouseEnterDelayTimer)
    oldMouseLeaveHandler?.(e)

    if (mouseEnterDelayTimer) {
      clearMouseEnterTimer()
      return
    }

    const timer = setTimeout(hide, mouseLeaveDelay)
    setMouseLeaveDelayTimer(timer)
  }, [clearMouseLeaveTimer, mouseEnterDelayTimer, clearMouseEnterTimer, hide, setMouseLeaveDelayTimer, mouseLeaveDelay])

  const newChild = React.cloneElement(child, {
    onMouseEnter: handleMouseEnter,
    onMouseLeave: handleMouseLeave,
  })

  if (isVisible) {
    const portal = ReactDOM.createPortal(
      <div>{content}</div>,
      portalContainer
    )
    return (
      <>
        {portal}
        {newChild}
      </>
    )
  }

  return newChild
}
about 4 years ago · Juan Pablo Isaza Relatório
Responde à pergunta
Encontrar trabalhos remotos

Descubra a nova forma de encontrar um emprego!

melhores empregos
Principais categorias de trabalho
Empresas
Postar vaga Preços Comercial
Jurídico
Termos e Condições Política de privacidade
© 2026 PeakU Inc. All Rights Reserved.
Andres GPT
Recomende algumas ofertas para mim
Preciso de ajuda