<header>
  <nav>
    <ul role="list">
      <li>File</li>
      <li>Edit</li>
      <li>Search</li>
      <li>Options</li>
      <li>Help</li>
    </ul>
  </nav>
</header>
<main contenteditable><span class="cursor active"></span></main>
<footer>
  MS-DOS Editor <span>
    Click anywhere in the editor to begin
  </span>
</footer>
$grey: #a8a8a8;
$blue: #0b00a8;
$teal: #00a7a8;

* {
  box-sizing: border-box;
}

body {
  min-height: 100vh;
  display: grid;
  grid-template-rows: min-content 1fr min-content;
  font-family: "Inconsolata", monospace;
  font-weight: bold;
  letter-spacing: 0.03em;
  font-size: 1.25rem;
  line-height: 1;
}

nav {
  background-color: $grey;

  ul {
    list-style: none;
    margin: 0;
    padding: 0.15rem 2rem;
    display: flex;

    li + li {
      margin-left: 1rem;
    }

    li:last-child {
      margin-left: auto;
    }
  }
}

main {
  background-color: $blue;
  color: $grey;
  padding: 1.25rem 1rem;
  box-shadow: inset 0 0 0 7px $blue, inset 0 0 0 9px currentcolor;
  position: relative;

  &:focus {
    outline: none;
  }

  &:before {
    content: "HELLOWORLD.BAT";
    position: absolute;
    top: 0;
    left: 50%;
    transform: translateX(-50%);
    background-color: $grey;
    color: $blue;
    padding: 0 0.75rem;
  }

  span {
    display: inline-flex;
  }
}

footer {
  background-color: $teal;
  color: #fff;
  padding: 0.05rem 1rem;
  display: flex;

  span {
    margin-left: 2rem;
  }
}

.cursor:after {
  content: "";
  display: inline-block;
  width: 1ch;
  height: 1.1em;
  background-color: $blue;
  margin: -0.03em 0 -0.03em -0.03em;
}

.cursor.active:after {
  animation: cursor 400ms ease-in-out infinite;
}

@keyframes cursor {
  0%,
  100% {
    background-color: $blue;
  }
  50% {
    background-color: $grey;
  }
}
View Compiled
// Described here:
// @link https://dev.to/5t3ph/helloworld-bat-vanillajs-plain-text-editor-25c7

const main = document.querySelector("main");
const hwArray = `HELLO WORLD`.split("");
const msgArray = `You may type your own content here.`.split("");
const typeSpeed = 130;
const hwDuration = typeSpeed * hwArray.length;
const msgDuration = typeSpeed * msgArray.length;
const msgDelay = hwDuration + 300;
const newLineDelay = hwDuration + msgDuration + 300;

// Type scripted messages
const type = (msgArray, target) => {
  msgArray.map((l, i) => {
    const letter = document.createTextNode(l);
    const delay = typeSpeed * i;

    setTimeout(() => {
      main.querySelector(target).appendChild(letter);
    }, delay);
  });
};

// Clear cursor animation from previous line
// Only works for new lines, doesn't work if you backspace to previous line
const clearCursor = () => {
  document.querySelector(".cursor.active").classList.remove("active");
};

// Create new line
const newLine = () => {
  const line = document.createElement("DIV");
  line.innerHTML = '<span class="cursor active"></span>';
  main.appendChild(line);
  clearCursor();
};

// Type initial greeting
setTimeout(() => {
  type(hwArray, "span");
}, 1000);

// Type instructions
setTimeout(() => {
  newLine();
  type(msgArray, "div span");
}, msgDelay + 1000);

// Type new line for user content
setTimeout(() => {
  newLine();
}, newLineDelay + 1000);

// If new line, drop "active" class
// from first active cursor to remove animation
main.addEventListener("keydown", (e) => {
  const key = e.keyCode;
  if (key === 13) {
    setTimeout(() => {
      clearCursor();
    }, 10);
  }
});
View Compiled

External CSS

This Pen doesn't use any external CSS resources.

External JavaScript

This Pen doesn't use any external JavaScript resources.