<div id="root"></div>
.progress-success {
  .ending-msg {
    color: green;
  }
}

.progress-failure {
  .ending-msg {
    color: red;
  }
}

.progress {
  .border {
    width: 200px;
    height: 30px;
    stroke-width: 2px;
    stroke: blue;
    fill: transparent;
  }
  
  .filling {
    width: 200px;
    height: 30px;
    fill: blue;
    animation: fillBar 1.5s ease-in-out 0s normal 1 forwards;
  }
  
  @keyframes fillBar {
    0% {
      width: 0;
    }
    30% {
      width: 80px;
    }
    70% {
      width: 120px;
    }
    100% {
      width: 200px;
    }
  }
}
View Compiled
function Progress() {
  const [loading, hasLoaded] = React.useState(false);

  React.useEffect(() => {
    const timer = setTimeout(() => {
      fetch('https://jsonplaceholder.typicode.com/posts')
        .then((response) => response.json())
        .then((json) => {
          hasLoaded(true);
        });
    }, 1550);

    return () => clearTimeout(timer);
  }, []);

  return (
    <div className={`progress ${loading ? "progress-success" : "progress-failure"}`}>
      {loading ? (
        <p className="ending-msg">Loaded!</p>
      ) : (
        <svg role="alert" aria-live="assertive">
          <rect x="1" y="1" className="border" rx="15" ry="15" />
          <rect x="1" y="1" className="filling" rx="15" ry="15" />
        </svg>
      )}
    </div>
  );
};

const rootElement = document.getElementById("root");
ReactDOM.render(<Progress />, rootElement);
View Compiled

External CSS

This Pen doesn't use any external CSS resources.

External JavaScript

  1. https://cdnjs.cloudflare.com/ajax/libs/react/16.7.0-alpha.2/umd/react.production.min.js
  2. https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.7.0-alpha.2/umd/react-dom.production.min.js