<div class="centered-content">
  <nav>
    <a target="_blank" href="https://support.apple.com/en-us/HT211008">&#xF8FF;</a>
    <a href="#">Button</a>
    <a href="#">Another button</a>
    <a href="#">A third button</a>
  </nav>
  <p>HTML-CSS-JS emulation of the new cursor in iPadOS 13.4.</p>
  <p>The cursor lock itself to anchor elements and change its shape over text elements.</p>
</div>

<div id="cursor" class="cursor">
  <div class="cursor__content"></div>
</div>
body {
  align-items: center;
  cursor: none;
  display: flex;
  font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica,
    Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol";
  height: 100vh;
  justify-content: center;
  overflow: hidden;
  user-select: none;
  width: 100vw;
}

.centered-content {
  text-align: center;
}

nav {
  margin-bottom: 1em;
}

p {
  line-height: 1.5em;
  margin: 0.2em;
  user-select: text;
}

a {
  color: #007aff;
  cursor: none;
  display: inline-block;
  padding: 0.6em 0.8em;
  position: relative;
  text-decoration: none;
  transform: translate(var(--translateX), var(--translateY)) scale(var(--scale));
  transition-duration: 0.1s;
  transition-timing-function: ease-out;
  transition-property: opacity;
  z-index: 1;

  --scale: 1;
  --translateX: 0;
  --translateY: 0;

  &:not(:hover) {
    transition-property: transform, opacity;
  }

  &:active {
    opacity: 0.5;
    transform: translate(var(--translateX), var(--translateY)) scale(1);
  }
}

.cursor {
  height: var(--height);
  left: var(--left);
  pointer-events: none;
  top: var(--top);
  transform: translate(-50%, -50%) scale(var(--scale));
  transition-property: width, height;
  width: var(--width);

  --top: -1em;
  --left: -1em;
  --width: 1em;
  --height: 1em;
  --scale: 1;
  --translateX: 0;
  --translateY: 0;

  &.is-locked {
    transition-property: width, height, left, top;

    .cursor__content {
      opacity: 0.06;
    }
  }

  &,
  &__content {
    position: absolute;
    transition-duration: 0.1s;
    transition-timing-function: ease-out;
  }

  &__content {
    background-color: #000;
    border-radius: 0.6em;
    bottom: 0;
    left: 0;
    opacity: 0.3;
    right: 0;
    top: 0;
    transform: translate(var(--translateX), var(--translateY));
    transition-property: "opacity";
  }
}
View Compiled
const cursor = document.querySelector("#cursor");

const DEFAULT_CURSOR_SIZE = cursor.style.getPropertyValue("--height");

let isCursorLocked = false;

document.addEventListener("mousedown", () => {
  if (!isCursorLocked) {
    cursor.style.setProperty("--scale", 0.9);
  }
});

document.addEventListener("mouseup", () => {
  if (!isCursorLocked) {
    cursor.style.setProperty("--scale", 1);
  }
});

document.addEventListener("mousemove", ({ x, y }) => {
  if (!isCursorLocked) {
    cursor.style.setProperty("--top", y + "px");
    cursor.style.setProperty("--left", x + "px");
  }
});

document.querySelectorAll("a").forEach((a) => {
  let rect = null;

  a.addEventListener(
    "mouseenter",
    ({ target }) => {
      isCursorLocked = true;

      rect = target.getBoundingClientRect();

      cursor.classList.add("is-locked");
      cursor.style.setProperty("--top", rect.top + rect.height / 2 + "px");
      cursor.style.setProperty("--left", rect.left + rect.width / 2 + "px");
      cursor.style.setProperty("--width", rect.width + "px");
      cursor.style.setProperty("--height", rect.height + "px");

      target.style.setProperty("--scale", 1.05);
    },
    { passive: true }
  );

  a.addEventListener(
    "mousemove",
    ({ target }) => {
      const halfHeight = rect.height / 2;
      const topOffset = (event.y - rect.top - halfHeight) / halfHeight;
      const halfWidth = rect.width / 2;
      const leftOffset = (event.x - rect.left - halfWidth) / halfWidth;

      cursor.style.setProperty("--translateX", `${leftOffset * 3}px`);
      cursor.style.setProperty("--translateY", `${topOffset * 3}px`);

      target.style.setProperty("--translateX", `${leftOffset * 6}px`);
      target.style.setProperty("--translateY", `${topOffset * 4}px`);
    },
    { passive: true }
  );

  a.addEventListener(
    "mouseleave",
    ({ target }) => {
      isCursorLocked = false;

      cursor.style.setProperty("--width", DEFAULT_CURSOR_SIZE);
      cursor.style.setProperty("--height", DEFAULT_CURSOR_SIZE);
      cursor.style.setProperty("--translateX", 0);
      cursor.style.setProperty("--translateY", 0);

      target.style.setProperty("--translateX", 0);
      target.style.setProperty("--translateY", 0);
      target.style.setProperty("--scale", 1);

      setTimeout(() => {
        if (!isCursorLocked) {
          cursor.classList.remove("is-locked");
        }
      }, 100);
    },
    { passive: true }
  );
});

document.querySelectorAll("p").forEach((p) => {
  p.addEventListener(
    "mouseover",
    () => {
      cursor.style.setProperty("--width", "0.2em");
      cursor.style.setProperty("--height", "1.5em");
    },
    { passive: true }
  );

  p.addEventListener(
    "mouseout",
    () => {
      cursor.style.setProperty("--width", DEFAULT_CURSOR_SIZE);
      cursor.style.setProperty("--height", DEFAULT_CURSOR_SIZE);
    },
    { passive: true }
  );
});
View Compiled

External CSS

This Pen doesn't use any external CSS resources.

External JavaScript

This Pen doesn't use any external JavaScript resources.