Random Quote Generator Using HTML, CSS and JavaScript

Beginner 11 views Oct 13, 2026

A random quote generator is a classic beginner project: click a button and a new quote appears. It teaches you about arrays of objects, random numbers, avoiding repeats and updating the page. In this tutorial you will build a Random Quote Generator with a smooth fade animation, a copy button and a share link, and a counter of how many quotes you have seen.

The quotes are stored in a plain array in your script, so it works offline and needs no API. At the end you will see how to load quotes from a server instead.

What You'll Learn

By the end of this tutorial you will know:

  • How to store data as an array of objects
  • How to pick a random item with Math.random()
  • How to avoid showing the same quote twice in a row
  • How to fade text out and in with CSS classes
  • How to copy text with the Clipboard API
  • How to create a share link with encodeURIComponent()

Features of This Random Quote Generator

  • New quote on every click or press of the space bar
  • Never repeats the same quote twice in a row
  • Fade animation
  • Copy to clipboard
  • Share on X (Twitter) link
  • Quote counter
  • Easy to add your own quotes

Prerequisites

You only need the basics: how to write a simple HTML page, a few CSS rules, and what a JavaScript variable and function are. Along with that, have a code editor such as Visual Studio Code and any modern browser ready. No frameworks, no build tools and no installs.

Project Structure

Create a new folder called random-quote-generator and add three empty files inside it:

PLAINTEXT
random-quote-generator/
├── index.html   → the page structure
├── style.css    → the look and layout
└── script.js    → the behaviour

Step 1: Create the HTML Structure

Create index.html. A card with the quote text, the author and three buttons.

HTML
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Random Quote Generator</title>
  <link rel="stylesheet" href="style.css">
</head>
<body>
  <main class="card">
    <p class="mark">“</p>
    <blockquote id="quote" class="quote" aria-live="polite">Click the button to get a quote.</blockquote>
    <p id="author" class="author"></p>

    <div class="btns">
      <button id="new">New quote</button>
      <button id="copy" class="ghost">Copy</button>
      <a id="share" class="ghost" target="_blank" rel="noopener">Share</a>
    </div>
    <p class="count">Quotes seen: <span id="seen">0</span></p>
    <p id="msg" class="msg" aria-live="polite"></p>
  </main>

  <script src="script.js"></script>
</body>
</html>

Step 2: Add the CSS Styling

Create style.css. A large decorative quotation mark sits above the quote text. The quote fades by changing its opacity with the fade class.

CSS
* {
  margin: 0;
  padding: 0;
  box-sizing: border-box;
}

body {
  font-family: "Segoe UI", Arial, sans-serif;
  background: #eef1f8;
  color: #1f2937;
  min-height: 100vh;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 20px;
}

.card {
  width: 100%;
  max-width: 520px;
  background: #fff;
  padding: 34px 30px;
  border-radius: 16px;
  box-shadow: 0 10px 30px rgba(31, 41, 55, 0.12);
  text-align: center;
}

.mark {
  font-size: 5rem;
  line-height: 0.6;
  color: #c7d2fe;
  font-family: Georgia, serif;
}

.quote {
  font-size: 1.4rem;
  line-height: 1.6;
  font-family: Georgia, "Times New Roman", serif;
  min-height: 7.5em;
  display: flex;
  align-items: center;
  justify-content: center;
  transition: opacity 0.25s;
}

.quote.fade, .author.fade { opacity: 0; }

.author {
  margin-top: 10px;
  font-weight: 700;
  color: #4f46e5;
  min-height: 1.4em;
  transition: opacity 0.25s;
}

.btns {
  display: flex;
  justify-content: center;
  gap: 10px;
  margin: 22px 0 12px;
  flex-wrap: wrap;
}

.btns button, .btns a {
  padding: 11px 20px;
  border: none;
  border-radius: 10px;
  background: #4f46e5;
  color: #fff;
  font-size: 0.95rem;
  text-decoration: none;
  cursor: pointer;
}

.btns .ghost { background: #eef2ff; color: #4338ca; }

.count { font-size: 0.85rem; color: #6b7280; }
.msg { min-height: 1.3em; color: #16a34a; font-weight: 600; font-size: 0.9rem; }

Step 3: Add the JavaScript

Create script.js. We keep the index of the last quote so we can make sure the next one is different. Changing the quote means fading out, swapping the text, and fading in again. A small busy flag stops fast clicks from stacking several fades on top of each other.

JAVASCRIPT
const QUOTES = [
  { text: 'The only way to do great work is to love what you do.', author: 'Steve Jobs' },
  { text: 'It always seems impossible until it is done.', author: 'Nelson Mandela' },
  { text: 'First, solve the problem. Then, write the code.', author: 'John Johnson' },
  { text: 'Simplicity is the soul of efficiency.', author: 'Austin Freeman' },
  { text: 'Whether you think you can or you think you cannot, you are right.', author: 'Henry Ford' },
  { text: 'The best way to predict the future is to invent it.', author: 'Alan Kay' },
  { text: 'Programs must be written for people to read, and only incidentally for machines to execute.', author: 'Harold Abelson' },
  { text: 'Do not watch the clock; do what it does. Keep going.', author: 'Sam Levenson' },
  { text: 'Well done is better than well said.', author: 'Benjamin Franklin' },
  { text: 'A journey of a thousand miles begins with a single step.', author: 'Lao Tzu' }
];

const quoteEl = document.getElementById('quote');
const authorEl = document.getElementById('author');
const seenEl = document.getElementById('seen');
const msg = document.getElementById('msg');
const shareEl = document.getElementById('share');

let last = -1;
let seen = 0;
let current = null;
let busy = false;     // true while a fade is running

function randomIndex() {
  let i;
  do {
    i = Math.floor(Math.random() * QUOTES.length);
  } while (i === last && QUOTES.length > 1);     // never the same one twice
  return i;
}

function newQuote() {
  if (busy) return;                              // ignore clicks during the fade
  busy = true;
  quoteEl.classList.add('fade');
  authorEl.classList.add('fade');

  setTimeout(() => {
    last = randomIndex();
    current = QUOTES[last];
    quoteEl.textContent = current.text;
    authorEl.textContent = '— ' + current.author;
    seenEl.textContent = ++seen;
    msg.textContent = '';

    const tweet = '“' + current.text + '” — ' + current.author;
    shareEl.href = 'https://twitter.com/intent/tweet?text=' + encodeURIComponent(tweet);

    quoteEl.classList.remove('fade');
    authorEl.classList.remove('fade');
    busy = false;
  }, 250);
}

document.getElementById('new').addEventListener('click', newQuote);

document.getElementById('copy').addEventListener('click', async () => {
  if (!current) return;
  const text = '“' + current.text + '” — ' + current.author;
  try {
    await navigator.clipboard.writeText(text);
    msg.textContent = 'Copied!';
  } catch (e) {
    // Clipboard blocked (for example inside an iframe): select the quote so Ctrl+C works
    const range = document.createRange();
    range.selectNodeContents(quoteEl);
    const sel = window.getSelection();
    sel.removeAllRanges();
    sel.addRange(range);
    msg.textContent = 'Quote selected - press Ctrl+C to copy';
  }
});

// Space bar = new quote, but not while a button or link has focus (it would click that one)
document.addEventListener('keydown', e => {
  const tag = e.target.tagName;
  if (e.code === 'Space' && tag !== 'BUTTON' && tag !== 'A' && tag !== 'INPUT' && tag !== 'TEXTAREA') {
    e.preventDefault();
    newQuote();
  }
});

newQuote();

How This Random Quote Generator Works

  • QUOTES is an array of objects with text and author. Adding a quote is adding one line.
  • randomIndex() keeps picking until the number differs from last. The extra check stops an endless loop if you ever have only one quote.
  • Fade: we add the fade class (opacity 0), wait 250 ms for the transition, change the text, and remove the class so it fades back in.
  • encodeURIComponent() converts spaces and special characters so the quote can be placed safely inside a URL.
  • busy is set to true at the start of a fade and back to false when it ends, so clicking quickly never skips or double-counts a quote.
  • Clipboard writing returns a promise, so we use await inside an async function. If the browser blocks clipboard access, the quote is selected instead so the visitor can press Ctrl+C.
  • Space bar shows a new quote, except when a button or link has focus, because then the space key would click that button.

Customization Guide

1. Add your own quotes

Add more objects to the array. 30 or more quotes make repeats rare.

2. Change the fade speed

Change 0.25s in the CSS and 250 in the JavaScript. They should match.

Future Enhancements

Once the basic version works, here are some ideas to practise with:

  • Load quotes from a public API with fetch()
  • Add categories such as Motivation or Programming
  • Save favourite quotes in localStorage
  • Show a different quote automatically every day

Troubleshooting Guide

The same quote appears twice

Check that last is updated every time and the do...while loop compares with it.

The Copy button only selects the text

Some browsers block the Clipboard API on pages that are not served over HTTPS or are shown inside a frame. The script then selects the quote, and Ctrl+C copies it.

The share link does not work

Make sure the text goes through encodeURIComponent().

Related Mini Projects

Want more practice? Try these beginner projects next:

Conclusion

You built a quote generator with random choices, animation and sharing. The same pattern works for jokes, facts, tips or flashcards.

Technologies Used

HTML5 CSS3 JavaScript

Live Output

See the project in action below. This is the live preview of the code you just learned.

Output Preview