Full Stack Development Course

Learn with us for free

Creating a Code Beautifer using HTML, CSS and Js only

Remember we're building a house. We'd need two main things: the structure (the HTML) and how it looks (the CSS), and some logic to handle stuff like what happens when you click buttons (the JavaScript). Today, the webpage we'll build does that for a simple "Code Beautifier" tool that formats code for you.

1. index.html - The Structure of the tool

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Code Beautifier</title>
    <link rel="stylesheet" href="style.css">
</head>
<body>
    <header>
          <a href="/blog/" style="text-decoration: none; color: inherit; transition: opacity 0.3s; opacity: 0.8; padding-right: 20px;">Learn HTML, CSS and JS for free</a>     
    </header>
     <div id="notification-container"></div>
    <div class="container">
        <h1> Code Beautifier</h1>
        <textarea id="code-input" placeholder="Paste your code here..."></textarea>
        <div class="button-container">
          <button id="beautify-btn">Beautify</button>
          <button id="minify-btn">Minify</button>
        </div>

        <div class="code-output-container">
            <pre><code id="code-output"></code></pre>
            <button class="copy-code-btn">Copy</button>
            <button class="download-code-btn">Download</button>
          </div>
      </div>

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

So, in short, the index.html file sets up all the pieces (like a text box, a title, buttons, and a place to show the results) that make up the Code Beautifier webpage.

2. script.js - The Brains of the Tool

This file makes the page interactive. It's what happens when you click the buttons!

document.addEventListener('DOMContentLoaded', function() {
    const inputArea = document.getElementById('code-input');
    const outputArea = document.getElementById('code-output');
    const beautifyButton = document.getElementById('beautify-btn');
    const minifyButton = document.getElementById('minify-btn');
    const copyButtons = document.querySelectorAll('.copy-code-btn');
    const downloadButton = document.querySelector('.download-code-btn');
    const notificationContainer = document.getElementById('notification-container');

    beautifyButton.addEventListener('click', function() {
       try {
        const code = inputArea.value;
        const language = detectLanguage(code);
        let formattedCode;

        switch (language) {
            case 'html':
                formattedCode = beautifyHTML(code);
                 break;
            case 'css':
                 formattedCode = beautifyCSS(code);
                 break;
            case 'json':
                 formattedCode = beautifyJSON(code);
                 break;
            case 'python':
                 formattedCode = beautifyPython(code);
                 break;
            default: // javascript
                formattedCode = beautifyCode(code);
        }
        outputArea.textContent = formattedCode;
         } catch (error) {
          showNotification('Error during beautifying.', 'error');
        }
    });

    minifyButton.addEventListener('click', function(){
        try {
          const code = inputArea.value;
          const language = detectLanguage(code);
          let minifiedCode;

           switch(language) {
               case 'html':
                 minifiedCode = minifyHTML(code);
                 break;
                case 'css':
                  minifiedCode = minifyCSS(code);
                  break;
                case 'json':
                     minifiedCode = minifyJSON(code);
                     break;
                case 'python':
                   minifiedCode = minifyPython(code);
                     break;
                default: // javascript
                   minifiedCode = minifyCode(code);
           }
           outputArea.textContent = minifiedCode;
       } catch (error) {
            showNotification('Error during minifying.', 'error');
        }
    });

    copyButtons.forEach(button => {
        button.addEventListener('click', function(){
            const codeToCopy = this.previousElementSibling.querySelector('code').textContent;
            copyCode(codeToCopy);
        });
    });

    downloadButton.addEventListener('click', function() {
        try {
            const code = outputArea.textContent;
            const language = detectLanguage(inputArea.value);
            let fileExtension;
              switch(language){
                  case 'html':
                    fileExtension = 'html';
                    break;
                    case 'css':
                        fileExtension = 'css';
                        break;
                   case 'json':
                    fileExtension = 'json';
                    break;
                   case 'python':
                    fileExtension = 'py';
                    break;
                   default:
                    fileExtension = 'js';
            }

            downloadCode(code, `code.${fileExtension}`);
            showNotification('Code downloaded successfully!', 'success');
        } catch(error) {
             showNotification('Error during download.', 'error');
         }
    });

     function detectLanguage(code) {
        const trimmedCode = code.trimStart();

          if(trimmedCode.startsWith('<!DOCTYPE html>') || trimmedCode.startsWith('<html')) {
            return 'html';
          } else if(trimmedCode.startsWith('{') || trimmedCode.startsWith('[')){
              try {
                  JSON.parse(trimmedCode);
                  return 'json';
              } catch (e){

              }
          } else if(trimmedCode.startsWith('/*') || trimmedCode.startsWith('.') || trimmedCode.startsWith('#') || trimmedCode.startsWith('@') || trimmedCode.startsWith('body') || trimmedCode.startsWith('div')){
                return 'css';
          } else if(trimmedCode.startsWith('def ') || trimmedCode.startsWith('import ') || trimmedCode.startsWith('class ' ) || trimmedCode.startsWith('from ') || trimmedCode.startsWith('print(') || trimmedCode.startsWith('if ') || trimmedCode.startsWith('while ') || trimmedCode.startsWith('for ') || trimmedCode.startsWith('try ') || trimmedCode.startsWith('except ') || trimmedCode.startsWith('finally ') || trimmedCode.startsWith('with ') || trimmedCode.startsWith('return ') || trimmedCode.startsWith('raise ') || trimmedCode.startsWith('assert ') || trimmedCode.startsWith('break ') || trimmedCode.startsWith('continue ') || trimmedCode.startsWith('global ') || trimmedCode.startsWith('nonlocal ') || trimmedCode.startsWith('lambda ') || trimmedCode.startsWith('pass ') || trimmedCode.startsWith('del ') || trimmedCode.startsWith('yield ') || trimmedCode.startsWith('async ') || trimmedCode.startsWith('await ')){
                return 'python'
          }
          else if(trimmedCode.startsWith('function ') || trimmedCode.startsWith('const ') || trimmedCode.startsWith('let ') || trimmedCode.startsWith('var ') || trimmedCode.includes('=>') || trimmedCode.includes('function(')){
              return 'javascript';
          }
          return 'javascript';
    }

    function beautifyCode(code) {
        let lines = code.split('\n');
        let indentLevel = 0;
        let beautifiedLines = [];

        for (let line of lines) {
            line = line.trim();
            if (line.endsWith('{')) {
                beautifiedLines.push('  '.repeat(indentLevel) + line);
                indentLevel++;
            } else if (line.startsWith('}')) {
                indentLevel = Math.max(0, indentLevel - 1);
                beautifiedLines.push('  '.repeat(indentLevel) + line);
            } else {
                beautifiedLines.push('  '.repeat(indentLevel) + line);
            }
        }
        return beautifiedLines.join('\n');
    }

    function minifyCode(code) {
        return code.replace(/\s+/g, ' ').trim();
    }

     function beautifyHTML(code) {
        return code.replace(/></g, '>\n<').replace(/<(.*?)>/g, '<$1>\n').replace(/\n\s*\n/g, '\n').trim();
    }


    function minifyHTML(code) {
       return code.replace(/>\s+</g,'><').replace(/\s+/g, ' ').trim();
    }

     function beautifyCSS(code) {
       return code.replace(/\{/g, '{\n  ').replace(/\}/g, '\n}\n').replace(/;/g, ';\n  ').replace(/\n\s*\n/g, '\n').trim();
    }

    function minifyCSS(code) {
        return code.replace(/\s+/g, ' ').replace(/{\s+/g, '{').replace(/\s+}/g, '}').replace(/:\s+/g, ':').replace(/;\s+/g,';').trim();
    }
     function beautifyJSON(code) {
            try {
                const parsed = JSON.parse(code);
                return JSON.stringify(parsed, null, 2);
            } catch (e) {
                 return code;
            }
     }

    function minifyJSON(code) {
         return code.replace(/\s+/g, '').trim();
    }
  function beautifyPython(code) {
     return code.replace(/:\s*\n/g,':\n    ').replace(/(\n\s*)?(def|class|for|if|while|with|try|except|finally)\b/g, '\n$2')
            .replace(/\n\s*\n/g, '\n')
           .trim();
    }

  function minifyPython(code){
      return code.replace(/\s+/g, ' ').trim();
  }
    function copyCode(text) {
        navigator.clipboard.writeText(text)
            .then(() => {
                 showNotification('Code copied to clipboard!', 'success');
            })
            .catch(err => {
                 showNotification('Failed to copy code.', 'error');
                console.error('Failed to copy text: ', err);
            });
    }
    function downloadCode(code, filename) {
        const blob = new Blob([code], { type: 'text/plain' });
        const url = URL.createObjectURL(blob);
        const a = document.createElement('a');
        a.href = url;
        a.download = filename;
        document.body.appendChild(a);
        a.click();
        document.body.removeChild(a);
        URL.revokeObjectURL(url);
    }
    function showNotification(message, type = 'success') {
        const notification = document.createElement('div');
        notification.classList.add('notification', type);
        notification.textContent = message;
        notificationContainer.appendChild(notification);
        setTimeout(() => {
            notification.classList.add('show');
        }, 10);

        setTimeout(() => {
            notification.classList.remove('show');
            setTimeout(() => {
                notificationContainer.removeChild(notification);
            }, 300);
        }, 2000);
    }
});

In summary, script.js makes the buttons work, grabs the code, formats it, and shows the results. It handles errors, copies, downloads, and gives you little feedback messages. It's the action part of your tool.

How They Work Together

  1. HTML builds the structure: You create the text box, the buttons, and the output area in index.html.
  2. CSS styles the look: The CSS file (style.css, not shown yet) makes the webpage look pretty.
  3. JavaScript adds interactivity: script.js makes the buttons work when you click them. It grabs the code you paste in, formats it, shows it to you, and enables you to copy or download it.

3. style.css: The Style Guide for the Webpage

CSS (Cascading Style Sheets) is like the stylist for your website. While HTML provides the structure (like the walls and rooms of a house), CSS is responsible for how everything looks: colors, fonts, sizes, layouts, and more.

Main CSS Concepts

Walking Through the CSS Code

/* ===================================================================== Variables and Global Styles ===================================================================== */
:root {
  --primary-color: #6c63ff;
  --primary-color-light: #857dff;
  --secondary-color: #56ccf2;
  --secondary-color-light: #72d4f5;
  --background-color: #f5f7fa;
  --text-color: #2c3e50;
  --text-color-light: #47596a;
  --card-background: #ffffff;
  --shadow-color: rgba(0, 0, 0, 0.1);
  --code-background: #f7f7f7;
  --border-color: #e0e0e0;
  --border-color-light: #e8e8e8;
  --gradient-start: #e1f5fe;
  --gradient-end: #e3f2fd;
  /* Typography */
  --base-font: "Roboto", sans-serif;
  --heading-font: "Montserrat", sans-serif;
  --code-font: "Fira Code", monospace;
  /* Spacing */
  --base-padding: 3rem;
  --small-padding: 2.2rem;
  --tiny-padding: 1.7rem;
  /* Transitions */
  --base-transition: 0.3s ease-in-out;
  --fast-transition: 0.2s ease-in-out;
  /* Shadows */
  --shadow-sm: 0 2px 4px var(--shadow-color);
  --shadow-md: 0 4px 8px var(--shadow-color);
  --shadow-lg: 0 8px 20px var(--shadow-color);
}

These variables allow you to change the colours, spacing and fonts of your website in one place, without having to update each specific style.

/* ===================================================================== Body Styles ===================================================================== */
body {
  font-family: var(--base-font);
  margin: 0;
  background: linear-gradient(45deg, var(--gradient-start), var(--gradient-end));
  background-size: 300% 300%;
  animation: gradientAnimation 15s ease infinite;
  display: flex;
  flex-direction: column;
  min-height: 100vh;
  color: var(--text-color);
  transition: background-color var(--base-transition);
    background-attachment: fixed;
    overflow-x: hidden;
}

@keyframes gradientAnimation {
  0% {
    background-position: 0% 50%;
  }
  50% {
    background-position: 100% 50%;
  }
  100% {
    background-position: 0% 50%;
  }
}
/* ===================================================================== Header Styles ===================================================================== */
header {
  padding: 1rem var(--base-padding);
  background-color: rgba(255, 255, 255, 0.15);
  backdrop-filter: blur(5px);
  display: flex;
  justify-content: flex-start;
    border-bottom: 1px solid rgba(0, 0, 0, 0.1);
    box-shadow: 0 2px 4px rgba(0, 0, 0, 0.05);
  transition: background-color var(--base-transition), box-shadow var(--base-transition);
}

header a {
  color: inherit;
  text-decoration: none;
  transition: opacity var(--fast-transition);
  opacity: 0.8;
  font-weight: 500;
    display: inline-block;
    padding-right: 20px;
}

header a:hover {
  opacity: 1;
}
/* ===================================================================== Container Styles ===================================================================== */
.container {
  background-color: var(--card-background);
  padding: var(--base-padding);
  border-radius: 15px;
  box-shadow: var(--shadow-md);
  width: 92%;
  max-width: 800px;
    transition: box-shadow var(--base-transition), transform var(--base-transition);
  margin: auto;
  margin-top: 3rem;
  margin-bottom: 3rem;
}

.container:hover {
  transform: translateY(-3px);
    box-shadow: var(--shadow-lg);
}
/* ===================================================================== Heading Styles ===================================================================== */
h1 {
  font-family: var(--heading-font);
  text-align: center;
  margin-bottom: 2rem;
  color: var(--primary-color);
    text-shadow: 1px 1px 2px rgba(0, 0, 0, 0.06);
  font-size: 2.6rem;
  font-variant-numeric: lining-nums proportional-nums;
    letter-spacing: -0.02rem;
  line-height: 1.2;
  transition: color var(--base-transition), text-shadow var(--base-transition);
}
/* ===================================================================== Textarea Styles ===================================================================== */
textarea {
  width: 100%;
  min-height: 220px;
  padding: 16px;
  border: 2px solid var(--border-color);
  border-radius: 10px;
  box-sizing: border-box;
  font-family: var(--code-font);
  white-space: pre-wrap;
    overflow-wrap: break-word;
  resize: vertical;
  outline: none;
  transition: border-color var(--base-transition), box-shadow var(--base-transition);
    line-height: 1.6;
    box-shadow: var(--shadow-sm);
}

textarea:focus {
  border-color: var(--primary-color);
  box-shadow: 0 0 5px rgba(var(--primary-color), 0.25);
}
/* ===================================================================== Preformatted Code Styles ===================================================================== */
.code-output-container {
  position: relative;
}

pre {
  background-color: var(--code-background);
  padding: 18px;
  border-radius: 10px;
  overflow-x: auto;
    white-space: pre-wrap;
  line-height: 1.7;
  font-family: var(--code-font);
    font-size: 1rem;
    box-shadow: var(--shadow-sm);
    margin-bottom: 2em;
    transition: background-color var(--base-transition), box-shadow var(--base-transition);
}

pre code {
  display: block;
}
/* ===================================================================== Button Styles ===================================================================== */
.button-container {
  display: flex;
  justify-content: center;
  margin: 2.5em 0;
}

button {
  margin: 0 16px;
  padding: 14px 28px;
  color: white;
  border: none;
  border-radius: 8px;
  cursor: pointer;
  transition: all var(--base-transition);
  box-shadow: var(--shadow-md);
    font-size: 1.1rem;
    font-weight: 500;
    position: relative;
    overflow: hidden;
    background: transparent;
}
button#beautify-btn{
    background: linear-gradient(135deg, var(--primary-color), var(--secondary-color));
}
button#minify-btn {
    background: #ffffff;
    color: var(--text-color);
    border: 1px solid var(--border-color);
}
button::before {
    content: "";
    position: absolute;
    top: 0;
    left: 0;
    width: 100%;
    height: 100%;
    background: rgba(255, 255, 255, 0.15);
    transform: scaleX(0);
    transform-origin: left;
    transition: transform 0.3s ease;
}
button:hover::before {
    transform: scaleX(1);
}
button#minify-btn:hover{
    background:#f5f7fa;
}
button:hover {
  transform: translateY(-3px);
  box-shadow: var(--shadow-lg);
}

button:focus {
  outline: none;
    box-shadow: 0 0 0 3px rgba(var(--primary-color), 0.3);
}
/* ===================================================================== Copy Code Button Styles ===================================================================== */
.copy-code-btn {
    position: absolute;
    top: 10px;
    right: 10px;
    padding: 8px 12px;
    background-color: rgba(255, 255, 255, 0.8);
    border: 1px solid var(--border-color);
    border-radius: 6px;
    cursor: pointer;
    font-size: 0.85rem;
    color: var(--text-color);
    transition: background-color var(--base-transition), transform var(--fast-transition), box-shadow var(--base-transition);
    box-shadow: var(--shadow-sm);
}

.copy-code-btn:hover {
    background-color: rgba(255, 255, 255, 1);
    transform: translateY(-2px);
    box-shadow: var(--shadow-md)
}

.copy-code-btn:focus {
    outline: none;
    box-shadow: 0 0 0 2px rgba(var(--primary-color), 0.3);
}
/* ===================================================================== Download Code Button Styles ===================================================================== */
.download-code-btn {
    position: absolute;
    top: 45px;
    right: 10px;
    padding: 8px 12px;
    background-color: rgba(255, 255, 255, 0.8);
    border: 1px solid var(--border-color);
    border-radius: 6px;
    cursor: pointer;
    font-size: 0.85rem;
    color: var(--text-color);
    transition: background-color var(--base-transition), transform var(--fast-transition), box-shadow var(--base-transition);
    box-shadow: var(--shadow-sm);
}

.download-code-btn:hover {
    background-color: rgba(255, 255, 255, 1);
    transform: translateY(-2px);
    box-shadow: var(--shadow-md)
}

.download-code-btn:focus {
    outline: none;
    box-shadow: 0 0 0 2px rgba(var(--primary-color), 0.3);
}
/* ===================================================================== Notification Styles ===================================================================== */
#notification-container {
  position: fixed;
  top: 20px;
  left: 50%;
  transform: translateX(-50%);
    z-index: 1000;
  display: flex;
  flex-direction: column;
    align-items: center;
    pointer-events: none; /* Allows clicks to pass through */
}

.notification {
  background-color: #ffffff;
  color: var(--text-color);
  padding: 12px 20px;
  border-radius: 8px;
  box-shadow: var(--shadow-md);
  margin-bottom: 10px;
    opacity: 0;
    transition: opacity 0.3s ease, transform 0.3s ease;
    transform: translateY(-20px);
  pointer-events: auto;
}

.notification.show {
    opacity: 1;
    transform: translateY(0);
}

.notification.success {
  background-color: #e8f5e9;
  color: #388e3c;
  border: 1px solid #c8e6c9;
}

.notification.error {
  background-color: #ffebee;
  color: #d32f2f;
  border: 1px solid #ef9a9a;
}
/* ===================================================================== Responsive Adjustments ===================================================================== */
@media (max-width: 768px) {
  body {
    padding: 0;
  }
  header {
    padding: 1rem var(--small-padding);
  }
  .container {
    padding: var(--small-padding);
    width: 95%;
    margin-top: 2rem;
    margin-bottom: 2rem;
  }
  h1 {
    font-size: 2.2rem;
    margin-bottom: 1.8em;
  }
  textarea {
    font-size: 0.95rem;
    min-height: 200px;
  }
  pre {
    font-size: 0.95rem;
  }
  button {
    padding: 12px 24px;
    font-size: 1rem;
    margin: 0 10px;
  }
  .copy-code-btn {
    padding: 6px 10px;
    font-size: 0.8rem;
    top: 8px;
    right: 8px;
  }
  .download-code-btn {
    padding: 6px 10px;
    font-size: 0.8rem;
    top: 40px;
    right: 8px;
  }
  #notification-container {
    top: 10px;
  }
}

@media (max-width: 576px) {
  header {
    padding: 1rem var(--tiny-padding);
  }
  .container {
    padding: var(--tiny-padding);
    margin-top: 1.5rem;
    margin-bottom: 1.5rem;
  }
  h1 {
    font-size: 2rem;
    margin-bottom: 1.5em;
  }
  textarea {
    font-size: 0.9rem;
    min-height: 180px;
  }
  pre {
    font-size: 0.85rem;
  }
  button {
    padding: 10px 20px;
    font-size: 0.95rem;
    margin: 0 8px;
  }
  .copy-code-btn {
    padding: 5px 8px;
    font-size: 0.75rem;
    top: 6px;
    right: 6px;
  }
  .download-code-btn {
      padding: 5px 8px;
    font-size: 0.75rem;
    top: 38px;
    right: 6px;
  }
}

Stylistic Choices and Why They Are Made

In summary, this CSS file styles your Code Beautifier tool, giving it a modern, clean, and user-friendly appearance. It uses variables, transitions, and responsive design to make the tool effective and easy to use.

This is a lot to take in at once, but with practice and time, these concepts will become second nature to you!