How to Create a Typewriter Text with Pure CSS

You'll agree that a text that looks like it is being typed across the screen looks quite attractive. Did you know that you can apply a typewriter effect to your text by using pure CSS? Now we are going to do that together, step by step!

Create HTML

  • Use a <div> element with a class name "typewriter".
  • Add a heading (<h1>) within the <div>.
<div class="typewriter">
  <h1>Once upon a time.</h1>
</div>

Add CSS

  • To ensure that each character has the same width and to make the transition between letters feel like being physically typed, set the font-family property to “monospace”.
  • Use the letter-spacing to define the space between letters and add a margin.
  • Set the overflow property to its “hidden” value to hide the content, which exceeds the width of the element.
  • Prevent the text from splitting into two lines by using the white-space property with the “nowrap” value.
  • Add the border-right property. That will be a blinking cursor at the end of the text. The blinking effect will be created by applying animation to our border.
  • Add animation with the animation property. You are free to choose the length of time and the number of steps.
  • Define keyframes for the animation. The first one will be for the typing, another one for the cursor.
.typewriter h1 {
  font-family: monospace;
  letter-spacing: .17em;
  margin: 0 auto;
  overflow: hidden;
  white-space: nowrap;
  border-right: .17em solid pink;
  animation: typing 3.5s steps(30, end), blinking-cursor .5s step-end infinite;
}

@keyframes typing {
  from {
    width: 0
  }
  to {
    width: 100%
  }
}

@keyframes blinking-cursor {
  from,
  to {
    border-color: transparent
  }
  50% {
    border-color: pink;
  }
}

Now it’s high time we put it all together and see the result.

Example of creating a typewriter text:

<!DOCTYPE html>
<html>
  <head>
    <title>Title of the document</title>
    <style>
      .typewriter h1 {
        font-family: monospace;/* Web-safe typewriter-like font */
        overflow: hidden;/* Ensures the content is not revealed until the animation */
        border-right: .17em solid pink;/* The typewriter cursor */
        white-space: nowrap;/* Keeps the content on a single line */
        margin: 0 auto;/* Gives that scrolling effect as the typing happens */
        letter-spacing: .17em;/* Adjust as needed */
        animation: typing 3.5s steps(30, end), blinking-cursor .5s step-end infinite;
      }
      /* The typing effect */
      @keyframes typing {
        from {
          width: 0
        }
        to {
          width: 100%
        }
      }
      /* The typewriter cursor effect */
      @keyframes blinking-cursor {
        from,
        to {
          border-color: transparent
        }
        50% {
          border-color: pink;
        }
      }
    </style>
  </head>
  <body>
    <div class="typewriter">
      <h1>Once upon a time...</h1>
    </div>
  </body>
</html>

Example of creating a typewriter text with the animation, animation-fill-mode, and animation-delay properties:

<!DOCTYPE html>
<html>
  <head>
    <title>Title of the document</title>
    <style>
      .content p {
        border-right: .15em solid orange;
        font-family: "Courier";
        font-size: 14px;
        white-space: nowrap;
        overflow: hidden;
      }
      .content p:nth-child(1) {
        width: 7.3em;
        -webkit-animation: type 2s steps(40, end);
        animation: type 2s steps(40, end);
        -webkit-animation-fill-mode: forwards;
        animation-fill-mode: forwards;
      }
      .content p:nth-child(2) {
        width: 11.5em;
        opacity: 0;
        -webkit-animation: type2 2s steps(40, end);
        animation: type2 2s steps(40, end);
        -webkit-animation-delay: 2s;
        animation-delay: 2s;
        -webkit-animation-fill-mode: forwards;
        animation-fill-mode: forwards;
      }
      .content p:nth-child(3) {
        width: 7.3em;
        opacity: 0;
        -webkit-animation: type3 5s steps(20, end), blink .5s step-end infinite alternate;
        animation: type3 5s steps(20, end), blink .5s step-end infinite alternate;
        -webkit-animation-delay: 4s;
        animation-delay: 4s;
        -webkit-animation-fill-mode: forwards;
        animation-fill-mode: forwards;
      }
      @keyframes type {
        0% {
          width: 0;
        }
        99.9% {
          border-right: .15em solid #82B533;
        }
        100% {
          border: none;
        }
      }
      @-webkit-keyframes type {
        0% {
          width: 0;
        }
        99.9% {
          border-right: .15em solid #82B533;
        }
        100% {
          border: none;
        }
      }
      @keyframes type2 {
        0% {
          width: 0;
        }
        1% {
          opacity: 1;
        }
        99.9% {
          border-right: .15em solid #82B533;
        }
        100% {
          opacity: 1;
          border: none;
        }
      }
      @-webkit-keyframes type2 {
        0% {
          width: 0;
        }
        1% {
          opacity: 1;
        }
        99.9% {
          border-right: .15em solid #82B533;
        }
        100% {
          opacity: 1;
          border: none;
        }
      }
      @keyframes type3 {
        0% {
          width: 0;
        }
        1% {
          opacity: 1;
        }
        100% {
          opacity: 1;
        }
      }
      @-webkit-keyframes type3 {
        0% {
          width: 0;
        }
        1% {
          opacity: 1;
        }
        100% {
          opacity: 1;
        }
      }
      @keyframes blink {
        50% {
          border-color: transparent;
        }
      }
      @-webkit-keyframes blink {
        50% {
          border-color: tranparent;
        }
      }
    </style>
  </head>
  <body>
    <div class="content">
      <p>
        Lorem Ipsum
      </p>
      <p>
        Lorem ipsum is simply a false texte...
      </p>
      <p>
        Lorem Ipsum
      </p>
    </div>
  </body>
</html>

Example of creating a typewriter text with a styled cursor:

<!DOCTYPE html>
<html>
  <head>
    <title>Title of the document</title>
    <style>
      body {
        padding: 40px;
        background-color: #666666;
      }
      #main {
        height: 40px;
        white-space: nowrap;
        overflow: hidden;
        font-family: 'Source Code Pro', monospace;
        font-size: 28px;
        color: rgba(255, 255, 255, .70);
        position: relative;
      }
      #border {
        border-bottom: solid 3px rgba(0, 255, 0, .75);
        position: absolute;
        right: -7px;
        width: 20px;
      }
      /* Animation */
      #main {
        animation: animated-text 2s steps(30, end) 1s 1 normal both
      }
      #border {
        animation: animated-cursor 600ms steps(30, end) infinite;
      }
      /* text animation */
      @keyframes animated-text {
        from {
          width: 0;
        }
        to {
          width: 480px;
        }
      }
      /* cursor animations */
      @keyframes animated-cursor {
        from {
          border-bottom-color: rgba(0, 255, 0, .75);
        }
        to {
          border-bottom-color: transparent;
        }
      }
    </style>
  </head>
  <body>
    <div id="main">
      Once upon a time...
      <div id="border"></div>
    </div>
  </body>
</html>

Example of adding a cursor without a typing effect:

<!DOCTYPE html>
<html>
  <head>
    <title>Title of the document</title>
    <style>
      body {
        padding: 40px;
        background-color: #8EBF43;
      }
      p {
        white-space: nowrap;
        overflow: hidden;
        font-family: 'Source Code Pro', monospace;
        font-size: 28px;
        color: rgba(255, 255, 255, .70);
      }
      /* Animation */
      p {
        animation: animated-text 3s steps(30, end) 1s 1 normal both;
      }
      /* text animation */
      @keyframes animated-text {
        from {
          width: 0;
        }
        to {
          width: 472px;
        }
      }
    </style>
  </head>
  <body>
    <p>This text doesn’t have a typewriter effect.</p>
  </body>
</html>

Example of adding a smooth typing effect with a blinking cursor:

<!DOCTYPE html>
<html>
  <head>
    <title>Title of the document</title>
    <style>
      body {
        padding: 40px;
        background-color: #c13b17;
      }
      p {
        border-right: solid 5px rgba(255, 255, 255, .75);
        white-space: nowrap;
        overflow: hidden;
        font-family: 'Source Code Pro', monospace;
        font-size: 28px;
        color: rgba(255, 255, 255, .70);
      }
      /* Animation */
      p {
        animation: animated-text 4s linear 1s 1 normal both, animated-cursor 600ms linear infinite;
      }
      /* text animation */
      @keyframes animated-text {
        from {
          width: 0;
        }
        to {
          width: 456px;
        }
      }
      /* cursor animations */
      @keyframes animated-cursor {
        from {
          border-right-color: rgba(255, 255, 255, .75);
        }
        to {
          border-right-color: transparent;
        }
      }
    </style>
  </head>
  <body>
    <p>To be or not to be</p>
  </body>
</html>

Example of creating a typewriter text moving to the left:

<!DOCTYPE html>
<html>
  <head>
    <title>Title of the document</title>
    <style>
      body {
        padding: 40px;
        background-color: #121212;
      }
      p {
        border-right: solid 3px rgba(0, 255, 0, .75);
        white-space: nowrap;
        overflow: hidden;
        font-family: 'Source Code Pro', monospace;
        font-size: 28px;
        color: rgba(255, 255, 255, .70);
        position: absolute;
        right: 10px;
      }
      /* Animation */
      p {
        animation: animated-text 4s steps(17, end) 1s 1 normal both, animated-cursor 600ms steps(17, end) infinite;
      }
      /* text animation */
      @keyframes animated-text {
        from {
          width: 0;
        }
        to {
          width: 286px;
        }
      }
      /* cursor animations */
      @keyframes animated-cursor {
        from {
          border-right-color: rgba(0, 255, 0, .75);
        }
        to {
          border-right-color: transparent;
        }
      }
    </style>
  </head>
  <body>
    <p>I am being typed.</p>
  </body>
</html>

Example of adding a typewriter effect with alternating text:

<!DOCTYPE html>
<html>
  <head>
    <title>Title of the document</title>
    <style>
      body {
        background-color: #71718c;
        color: #ffffff;
        font-size: 100px;
      }
      h1 {
        font-size: 30px;
      }
      .text-1 {
        animation: text1;
      }
      .text-2 {
        animation: text2;
      }
      .text-1,
      .text-2 {
        overflow: hidden;
        white-space: nowrap;
        display: inline-block;
        position: relative;
        animation-duration: 20s;
        animation-timing-function: steps(25, end);
        animation-iteration-count: infinite;
      }
      .text-1::after,
      .text-2::after {
        content: "|";
        position: absolute;
        right: 0;
        animation: caret infinite;
        animation-duration: 1s;
        animation-timing-function: steps(1, end);
      }
      @keyframes text2 {
        0%,
        50%,
        100% {
          width: 0;
        }
        60%,
        90% {
          width: 21.2em;
        }
      }
      @keyframes text1 {
        0%,
        50%,
        100% {
          width: 0;
        }
        10%,
        40% {
          width: 17em;
        }
      }
      @keyframes caret {
        0%,
        100% {
          opacity: 0;
        }
        50% {
          opacity: 1;
        }
      }
    </style>
  </head>
  <body>
    <h1>
      <span class="text-1">I am a great heading for your static web page</span>
      <span class="text-2">Really? And this is made without JavaScriipt?</span>
    </h1>
  </body>
</html>