Disclaimer: tutaj masz wytłumaczone eventy mouseover/out vs mouseenter/leave. Uzyłem tych ostatnich, żeby tooltip nie znikał jak najadę na niego myszką.
Do samego efektu pojawiania nie potrzebujesz JS'a. Można to zrobić cssem. Użyj JS tylko do tego, żeby dodać klasy.
JSFiddle
const tooltips = [...document.querySelectorAll('[data-tooltip]')];
tooltips.forEach(tooltip => {
const tooltipEl = document.createElement('div');
tooltipEl.classList.add('tooltip');
tooltipEl.innerText = tooltip.dataset.tooltip;
tooltip.appendChild(tooltipEl);
tooltip.addEventListener('mouseenter', () => {
// Tu stosujemy pewien trick
// Nie możemy jedną klasą zrobić display: block i opacity: 1,
// Dlatego, że nie będzie efektu płynnego pojawiania się
// transition nie działa jak element ma display: none i przejdziemy na opacity:1 display: block
// Dlatego najpierw dodajmy klase tooltip--visible, która powoduje,
// że element ma display: block (ale wciąż opacity: 0, więc jeszcze go nie widać),
// a później po chwili dopiero dodajemy klasę z opacity: 1
tooltipEl.classList.add('tooltip--visible');
setTimeout(() => tooltipEl.classList.add('tooltip--in'));
});
tooltip.addEventListener('mouseleave', () => {
// Tutaj jest odwrotność tego, co na górze
// Najpierw zabieramy klasę z opacity: 1,
// więc element płynnie znika, a dopiero jak zniknie, to dajemy display: none;
tooltipEl.classList.remove('tooltip--in');
setTimeout(() => tooltipEl.classList.remove('tooltip--visible'), 250);
});
});
Nie wiem, czy taki miał być efekt, ale mając ten kod na bank sobie go przerobisz do swoich potrzeb :)