JSFiddle - React, Tailwind, and code Playground

HTML

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <meta http-equiv="X-UA-Compatible" content="ie=edge" />
    <title>PingPong</title>
    <link rel="stylesheet" type="text/css" href="./style.css" />
  </head>
  <body>
    <div id="container">
      <div id="ball"></div>
      <div id="paddle-a" class="paddle"></div>
    </div>
    <script type="text/javascript" src="./script.js" />
  </body>
</html>

CSS

#container {
  background: green;
  position: fixed;
  width: 100vw;
  height: 100vh;
  padding: 0;
  margin:0;
}

#ball {
  width: 50px;
  height: 50px;
  border-radius: 50%;
  background-color: white;
  position: absolute;
}

.paddle {
  position: absolute;
  background: red;
  width: 20px;
  height: 100px;
}

Babel + JSX

// found here: http://paulbourke.net/geometry/pointlineplane/
const intersect = (x1, y1, x2, y2, x3, y3, x4, y4) => {
  // Check if none of the lines are of length 0
  if ((x1 === x2 && y1 === y2) || (x3 === x4 && y3 === y4)) {
    return false;
  }

  denominator = (y4 - y3) * (x2 - x1) - (x4 - x3) * (y2 - y1);

  // Lines are parallel
  if (denominator === 0) {
    return false;
  }

  let ua = ((x4 - x3) * (y1 - y3) - (y4 - y3) * (x1 - x3)) / denominator;
  let ub = ((x2 - x1) * (y1 - y3) - (y2 - y1) * (x1 - x3)) / denominator;

  // is the intersection along the segments
  if (ua < 0 || ua > 1 || ub < 0 || ub > 1) {
    return false;
  }

  // Return a object with the x and y coordinates of the intersection
  let x = x1 + ua * (x2 - x1);
  let y = y1 + ua * (y2 - y1);

  return { x, y };
};

class Paddle {
  constructor(name, element, x, y) {
    this.name = name;
    this.element = element;
    this.x = x || 0;
    this.y = y || 0;
    this.lastX = 0;
    this.lastY = 0;
    this.vx = 0;
    this.vy = 0;
    this.nextX = 0;
    this.nextY = 0;
    this.w = this.element.getBoundingClientRect().width;
    this.h = this.element.getBoundingClientRect().height;
    this.isDown = false;
    this.addEvents();
  }

  addEvents() {
    window.addEventListener("pointermove", e => {
      if (this.isDown) {
        this.lastX = this.x;
        this.lastY = this.y;
        this.x = e.x;
        this.y = e.y; 
      }
    });

    this.element.addEventListener("pointerdown", e => {
      this.isDown = true;
    });

    this.element.addEventListener("pointerup", () => {
      this.isDown = false;
    });

  }

  render() {
    this.vx = this.x - this.lastX;
    this.vy = this.y - this.lastY;
    // predict next point
    this.nextX = this.x + this.vx;
    this.nextY = this.y + this.vy;

    this.element.setAttribute(
      "style",
      `transform: translate(${this.x}px, ${this.y}px)`
    );
  }
}

class Ball {
  constructor(x, y) {
    this.element =...