<div id="app"></div>
* {
  box-sizing: border-box;
  margin: 0;
  padding: 0;
}
html {
  font-size: 62.5%;
  font-family: Arial;
}
button {
  font-family: inherit;
  font-size: inherit;
  padding: 0.4rem;
}
body {
  font-size: 1.6rem;
  padding: 2.4rem;
  height: 100vh;
}
#app {
  height: 100%;
  display: flex;
  flex-direction: column;
  justify-content: center;
  align-items: center;
  gap: 3.2rem;
}
.demo {
  width: 100%;
  height: 6.4rem;
  padding: 0 2.4rem;
  border: solid 1px;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1.6rem;
  width: fit-content;
}
.save-status {
  display: grid;
  border: solid 1px red;
}
.save-status span {
  grid-area: 1 / -1;
}
.hidden {
  visibility: hidden;
}
.right {
  display: flex;
}
.demo-section {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 1.6rem;
}
label {
  display: flex;
  align-items: center;
  gap: 0.8rem;
}
import { useState } from "https://cdn.skypack.dev/react@17.0.2";
import { render } from "https://cdn.skypack.dev/react-dom@17.0.2";
import classNames from "https://cdn.skypack.dev/classnames";

const messages = {
  saved: "Saved",
  saving: "Saving..."
};

const Demo = ({ shouldPreventLayoutShift = false }) => {
  const [isSaving, setIsSaving] = useState(false);

  const renderLabel = () => {
    if (shouldPreventLayoutShift) {
      return (
        <>
          <span className={classNames({ hidden: isSaving })}>
            {messages.saved}
          </span>
          <span className={classNames({ hidden: !isSaving })}>
            {messages.saving}
          </span>
        </>
      );
    }

    return isSaving ? messages.saving : messages.saved;
  };

  return (
    <div className="demo">
      <span class="save-status">{renderLabel()}</span>
      <div class="right">
        <button
          type="button"
          onClick={() => {
            setIsSaving(true);
            setTimeout(() => setIsSaving(false), 1000);
          }}
        >
          Toggle save state
        </button>
      </div>
    </div>
  );
};

const App = () => {
  const [shouldPreventLayoutShift, setShouldPreventLayoutShift] = useState(
    false
  );
  return (
    <>
      <div className="demo-section">
        <h2>Dynamic Text & Layout Shifts</h2>
        <p>Click the button. Observe that there is {shouldPreventLayoutShift ? 'no' : 'a'} layout shift.</p>
        <Demo shouldPreventLayoutShift={shouldPreventLayoutShift} />
        <label for="reflow">
          <input
            id="reflow"
            type="checkbox"
            onChange={(e) => setShouldPreventLayoutShift(e.target.checked)}
          />
          Prevent layout shift
        </label>
      </div>
    </>
  );
};

render(<App />, document.getElementById("app"));
View Compiled
Run Pen

External CSS

This Pen doesn't use any external CSS resources.

External JavaScript

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