JSFiddle - React, Tailwind, and code Playground

HTML

<div id="text"></div>
  
  <p>Lorem ipsum dolor sit amet, consectetur adipisicing elit. Nam rerum omnis, sunt, fugit optio, mollitia eos explicabo ex modi exercitationem iste earum! Quisquam ex ut, velit dolores culpa omnis sunt!</p>
  <img src="https://bipbap.ru/wp-content/uploads/2017/04/priroda_kartinki_foto_03.jpg" data-text="подпись 1" class="image">
<img src="https://st4.depositphotos.com/2012555/37952/i/1600/depositphotos_379525432-stock-photo-vintage-photo-butterfly-tree-flowers.jpg" data-text="подпись 2" class="image">

<ul>
  <li class="image">11111</li>
  <li class="image">222</li>
</ul>


<div class="circle-cursor circle-cursor--inner"></div>
<div class="circle-cursor circle-cursor--outer"></div>

CSS

html {
  cursor: none;
}

body {  
  margin: 0;
  --cursor-color: #000;  
}

.circle-cursor {
  position: fixed;
  left: 0;
  top: 0;
  pointer-events: none;
  border-radius: 50%;
  transition: background-color 100ms;
}

.circle-cursor--inner {
  width: 5px;
  height: 5px;
  left: -2.5px;
  top: -2.5px;
  z-index: 11000;
  background-color: var(--cursor-color);
}

.circle-cursor--inner.circle-cursor--hover {
  background-color: rgba(0,0,0,0);
}

.circle-cursor--outer {
  width: 30px;
  height: 30px;
  left: -15px;
  top: -15px;
  border: 1px solid var(--cursor-color);
  z-index: 12000;
  opacity: 0.2;
}

.circle-cursor--outer.circle-cursor--hover {
  background-color: var(--cursor-color);
}

img {
  max-width: 300px;
  margin-bottom: 55px;
}

li {
  margin-bottom: 20px;
}

#text {
  position: fixed;
  top: 0px;
  left: 0px;
  transition: transform 0.1s, opacity 0.1s;
}

JavaScript

var img = document.getElementsByTagName("img");
var text = document.getElementById("text");

for (var i = 0; i < img.length; i++) {

  img[i].addEventListener("mouseover", function() { 
    var alt = this.dataset.text;
    
    if (!text.textContent) {
    	text.textContent = alt;
    }
    
    if (text.style.opacity != 1) {
    	text.style.opacity = 1;
    }
    
    text.style.transform = `translate(${cxo}px, ${cyo}px)`;
  });

  img[i].addEventListener("mousemove", function() {
   	var alt = this.dataset.text;
    
    if (!text.textContent) {
    	text.textContent = alt;
    }
    
    if (text.style.opacity != 1) {
    	text.style.opacity = 1;
    }
    
    text.style.transform = `translate3d(${cxo}px, ${cyo}px, 0px)`;
  });


  img[i].addEventListener("mouseout", function() {
    text.style.opacity = 0;
  })
}

const cursorInner = document.querySelector('.circle-cursor--inner');
const cursorOuter = document.querySelector('.circle-cursor--outer');

let mx = window.innerWidth / 2;
let my = window.innerHeight / 2;
let cxi = mx,
  cyi = my,
  cxo = mx,
  cyo = my;

window.addEventListener('mousemove', (event) => {
  mx = event.clientX;
  my = event.clientY; 
});

function update() {
  const dxi = (mx - cxi) * 0.2;
  const dyi = (my - cyi) * 0.2;
  
  cxi += dxi;
  cyi += dyi;

  const dxo = (mx - cxo) * 0.07;
  const dyo = (my - cyo) * 0.07;
  cxo += dxo;
  cyo += dyo;

  cursorOuter.style.transform = `translate(${cxo}px, ${cyo}px)`;
  cursorInner.style.transform = `translate(${cxi}px, ${cyi}px)`;
  
  requestAnimationFrame(update);
}

requestAnimationFrame(update);

document.body.addEventListener('mouseover', (event) => {
  if (!event.target.closest('.image')) return;
  cursorInner.classList.add('circle-cursor--hover');
  cursorOuter.classList.add('circle-cursor--hover');
});

document.body.addEventListener('mouseout', (event) => {
  if (!event.target.closest('.image')) return;
  cursorInner.classList.remove('circle-cursor--hover');
 ...