If you’re looking to level up your front-end development skills by building a practical web utility, this is the guide for you.
We’ll code a fully functional Case Converter Tool from scratch using only HTML, CSS, and vanilla JavaScript.
This lightweight application allows users to paste their content and immediately transform it into standard formats like UPPERCASE, lowercase, Title Case, and Sentence case.
Alongside the text formatting, we’ll integrate a live character counter and set up functionality to export the final text as a PDF or Word document.
Grab your favorite code editor, and let’s dive in.
Prerequisites
Before you begin, you should have a basic familiarity with the following tools and concepts:
-
Core Web Technologies: A fundamental understanding of HTML structure, basic CSS styling, and JavaScript concepts like functions, array methods, and string manipulation.
-
Development Environment: A code editor installed on your computer (for example, Visual Studio Code) and a modern web browser to test your application locally.
Table of Contents
Step 1: Set Up Your Project
Before writing any code, you need to establish a clean directory structure for your application files.
First, you’ll need to initialize a workspace. Open your file manager and create a brand new directory to keep your work organized. Let’s name this directory case-converter-app.
Then you’ll generate the required files. Inside your newly created directory, set up the following three blank files:
-
index.html -
styles.css -
script.js
Step 2: Build the HTML Structure
Open the index.html file in your code editor. You’ll add the structural foundation of the tool here.
Add the following code into your index.html file:
Case Converter Tool
0
Characters
0
Words
0
Paragraphs
0
Sentences
Understanding this HTML:
-
: This links to an external library that allows JavaScript to generate PDF files directly in the user's browser. -
body {
background: linear-gradient(135deg, #e0eafc 0%, #cfdef3 100%);
min-height: 100vh;
display: flex;
justify-content: center;
align-items: center;
padding: 2rem;
color: #1e293b;
}.app-container {
background: #ffffff;
width: 100%;
max-width: 900px;
border-radius: 24px;
box-shadow: 0 20px 40px rgba(0,0,0,0.08);
padding: 2.5rem;
}.textarea-header {
display: flex;
justify-content: flex-end;
margin-bottom: 0.5rem;
}.tip-badge {
background: #fef08a;
color: #854d0e;
padding: 0.35rem 0.85rem;
border-radius: 20px;
font-size: 0.75rem;
font-weight: 600;
}textarea {
width: 100%;
height: 220px;
padding: 1.5rem;
border: 2px solid #e2e8f0;
border-radius: 16px;
font-size: 1rem;
resize: vertical;
outline: none;
transition: all 0.3s ease;
background: #f8fafc;
}textarea:focus {
border-color: #007bff;
background: #fff;
box-shadow: 0 0 0 4px rgba(0, 123, 255, 0.1);
}.button-grid {
display: flex;
flex-wrap: wrap;
gap: 0.75rem;
margin-top: 1.5rem;
}button {
padding: 0.75rem 1.25rem;
border: none;
border-radius: 12px;
font-size: 0.875rem;
font-weight: 600;
cursor: pointer;
transition: all 0.2s ease;
}.case-btn {
background: #f1f5f9;
color: #475569;
border: 1px solid #e2e8f0;
}.case-btn:hover {
background: #e2e8f0;
}/* The active class highlights the selected button */
.case-btn.active {
background: #007bff;
color: #fff;
border-color: #007bff;
box-shadow: 0 4px 12px rgba(0, 123, 255, 0.25);
}.divider {
height: 1px;
background: #e2e8f0;
margin: 1.5rem 0;
}.action-btn {
background: #fff;
border: 1px solid #cbd5e1;
}.action-btn:hover {
background: #f8fafc;
border-color: #94a3b8;
}.primary-action {
background: #007bff;
color: #fff;
border-color: #007bff;
}.primary-action:hover {
background: #0056b3;
border-color: #0056b3;
}.danger-action {
color: #ef4444;
border-color: #fca5a5;
background: #fef2f2;
}.danger-action:hover {
background: #fee2e2;
border-color: #f87171;
}.stats-panel {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(130px, 1fr));
gap: 1rem;
margin-top: 2rem;
background: #f8fafc;
padding: 1.5rem;
border-radius: 16px;
border: 1px solid #e2e8f0;
}.stat-box {
display: flex;
flex-direction: column;
align-items: center;
}.stat-value {
font-size: 1.75rem;
font-weight: 700;
}.stat-label {
font-size: 0.75rem;
color: #64748b;
text-transform: uppercase;
}
</code></pre>
<p>Understanding this CSS:</p>
<ul>
<li><p><code>body</code>: You use Flexbox to center the tool perfectly on the screen and apply a soft gradient background.</p>
</li>
<li><p><code>.app-container</code>: This creates a white, rounded card with a soft shadow to hold the user interface.</p>
</li>
<li><p><code>.case-btn.active</code>: You define an active state here. You'll use JavaScript to apply this class to the specific button the user clicks.</p>
</li>
</ul>
<p>At this stage, we've completely structured and styled the user interface. The tool will look like this:</p>
<img src="https://cdn.hashnode.com/uploads/covers/699c7b22cf5def0f6aaf982b/53e128aa-fb0d-47f3-8dca-9e3e0aa130c1.png" alt="Case Converter Tool screenshot" style="display:block;margin:0 auto" width="600" height="400" loading="lazy"><p>Right now, the front-end is visible, but the buttons are entirely static. To make the transformations actually work, we have to write the logic in JavaScript.</p>
<h2 id="heading-step-4-add-javascript-functionality">Step 4: Add JavaScript Functionality</h2>
<p>Now you need to make the tool interactive. Open the <code>script.js</code> file and add this code:</p>
<pre><code class="language-javascript">const textArea = document.getElementById('inputText');// Listen for typing to update statistics in real-time
textArea.addEventListener('input', updateStats);function updateStats() {
const text = textArea.value;document.getElementById('charCount').textContent = text.length;
const words = text.trim().split(/\s+/).filter(word => word.length > 0);
document.getElementById('wordCount').textContent = words.length;const sentences = text.split(/[.!?]+/).filter(sentence => sentence.trim().length > 0);
document.getElementById('sentenceCount').textContent = sentences.length;const paragraphs = text.split(/\n+/).filter(paragraph => paragraph.trim().length > 0);
document.getElementById('paragraphCount').textContent = paragraphs.length;
}function convertCase(event, type) {
let text = textArea.value;
if (!text) return;// Highlight the active button
const buttons = document.querySelectorAll('.case-btn');
buttons.forEach(btn => btn.classList.remove('active'));
if (event) {
event.target.classList.add('active');
}// Process the text
switch (type) {
case 'upper':
text = text.toUpperCase();
break;
case 'lower':
text = text.toLowerCase();
break;
case 'capitalized':
text = text.toLowerCase().replace(/\b\w/g, c => c.toUpperCase());
break;
case 'title':
const minorWords = ['a', 'an', 'the', 'and', 'but', 'or', 'for', 'nor', 'on', 'at', 'to', 'from', 'by'];
text = text.toLowerCase().split(' ').map((word, index) => {
if (index !== 0 && minorWords.includes(word)) return word;
return word.charAt(0).toUpperCase() + word.slice(1);
}).join(' ');
break;
case 'sentence':
text = text.toLowerCase().replace(/(^\s*\w|[\.\!\?]\n*\s*\w)/g, c => c.toUpperCase());
break;
case 'inverse':
text = text.split('').map(c => c === c.toUpperCase() ? c.toLowerCase() : c.toUpperCase()).join('');
break;
case 'alternate':
text = text.toLowerCase().split('').map((c, i) => i % 2 === 0 ? c : c.toUpperCase()).join('');
break;
}textArea.value = text;
updateStats();
}function copyToClipboard() {
if (!textArea.value) return;
textArea.select();
document.execCommand('copy');const copyBtn = document.querySelector('.copy-btn');
copyBtn.textContent="Copied!";
setTimeout(() => copyBtn.textContent="Copy To Clipboard", 1500);
}function clearText() {
textArea.value="";
updateStats();
document.querySelectorAll('.case-btn').forEach(btn => btn.classList.remove('active'));
}function downloadWord() {
if (!textArea.value) return;
const blob = new Blob([textArea.value], { type: 'application/msword' });
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = 'converted_text.doc';
a.click();
URL.revokeObjectURL(url);
}function downloadPDF() {
if (!textArea.value) return;
const { jsPDF } = window.jspdf;
const doc = new jsPDF();
const splitText = doc.splitTextToSize(textArea.value, 180);
doc.text(splitText, 15, 15);
doc.save('converted_text.pdf');
}
</code></pre>
<p>Understanding this JavaScript:</p>
<ul>
<li><p><code>addEventListener('input', ...)</code>: This listens to every single keystroke. Every time you type, it instantly recalculates the words, characters, and sentences.</p>
</li>
<li><p><code>convertCase(event, type)</code>: This function takes the selected style (like <code>upper</code> or <code>sentence</code>) and applies Regular Expressions (Regex) or array mapping to format the string. It also dynamically adds the <code>.active</code> CSS class to the specific button you clicked.</p>
</li>
<li><p><code>document.execCommand('copy')</code>: This is a browser command that copies the selected text directly to the user's clipboard.</p>
</li>
<li><p><code>new Blob()</code>: You use a Blob (Binary Large Object) to construct a file out of the text on the fly. This allows users to download a <code>.doc</code> file without needing a backend server.</p>
</li>
</ul>
<h2 id="heading-step-5-test-your-tool">Step 5: Test Your Tool</h2>
<p>You're now ready to evaluate your code in a real browser environment.</p>
<ol>
<li><p>Open the <code>case-converter-app</code> folder on your computer.</p>
</li>
<li><p>Double-click the <code>index.html</code> file to launch the application.</p>
</li>
<li><p>Paste a long paragraph into the text area to verify that the live statistics update accurately.</p>
</li>
<li><p>Switch between the formatting options to observe the immediate DOM manipulation, and test the export buttons to ensure files are downloading correctly.</p>
</li>
</ol>
<h2 id="heading-conclusion">Conclusion</h2>
<p>In this tutorial, you successfully engineered a browser-based Case Converter Tool using vanilla JavaScript.</p>
<p>You learned how to handle continuous user inputs, manipulate string data using Regular Expressions, and trigger local file downloads directly from the front end.</p>
<p>Most importantly, you learned that modern web browsers are highly capable of handling complex document modifications locally, removing the strict need for external backend servers. This method guarantees fast processing speeds and keeps user data completely private.</p>
<p>For a live demonstration of these concepts in a production environment, feel free to test out this <a href="https://99tools.net/case-converter/">Case Converter</a> and experience how seamlessly these text transformations operate.</p></section>
<div class="sidebar">
</div>
</div>
<hr><div class="post-full-author-header" data-test-label="author-header-with-bio">
<section class="author-card" data-test-label="author-card">
<img srcset="https://avatars.githubusercontent.com/u/254470266?v=4 60w" sizes="60px" src="https://avatars.githubusercontent.com/u/254470266?v=4" class="author-profile-image" alt="Bansidhar Kadiya" width="460" height="460" onerror="this.style.display='none'" loading="lazy" data-test-label="profile-image">
<section class="author-card-content ">
<span class="author-card-name">
<a href="https://www.freecodecamp.org/news/author/99tools/" data-test-label="profile-link">Bansidhar Kadiya
</a>
</span><p data-test-label="author-bio">Bansidhar Kadiya is a WordPress Developer and SEO specialist focused on building fast, practical web experiences. He is the creator of 99tools.net, a growing collection of free browser-based utilities designed to help developers, creators, and everyday users complete common tasks quickly and efficiently.</p>
</section>
</section></div>
<hr><p data-test-label="social-row-cta" class="social-row">
If you read this far, thank the author to show them you care. <button id="tweet-btn" class="cta-button" data-test-label="tweet-button">Say Thanks</button>
</p><div class="learn-cta-row" data-test-label="learn-cta-row">
<p>
Learn to code for free. freeCodeCamp's open source curriculum has helped more than 40,000 people get jobs as developers. <a href="https://www.freecodecamp.org/learn" class="cta-button" id="learn-to-code-cta" rel="noopener noreferrer" target="_blank">Get started</a>
</p>
</div></section>
<div class="banner-ad-bottom">
<div class="ad-text" data-test-label="ad-text">ADVERTISEMENT</div>
<div style="display: block; height: auto" id="gam-ad-bottom">
</div></div>
</article>
</div>
</main><footer class="site-footer">
<div class="footer-top">
<div class="footer-desc-col">
<p data-test-label="tax-exempt-status">freeCodeCamp is a donor-supported tax-exempt 501(c)(3) charity organization (United States Federal Tax Identification Number: 82-0779546)</p>
<p data-test-label="mission-statement">Our mission: to help people learn to code for free. We accomplish this by creating thousands of videos, articles, and interactive coding lessons - all freely available to the public.</p>
<p data-test-label="donation-initiatives">Donations to freeCodeCamp go toward our education initiatives, and help pay for servers, services, and staff.</p>
<p class="footer-donation" data-test-label="donate-text">
You can <a href="https://www.freecodecamp.org/donate/" class="inline" rel="noopener noreferrer" target="_blank">make a tax-deductible donation here</a>.
</p>
</div>
<div class="trending-guides" data-test-label="trending-guides">
<h2 id="trending-guides" class="col-header">Trending Books and Handbooks</h2>
<ul class="trending-guides-articles" aria-labelledby="trending-guides">
<li>
<a href="https://www.freecodecamp.org/news/build-consume-and-document-a-rest-api/" rel="noopener noreferrer" target="_blank">REST APIs
</a>
</li>
<li>
<a href="https://www.freecodecamp.org/news/how-to-write-clean-code/" rel="noopener noreferrer" target="_blank">Clean Code
</a>
</li>
<li>
<a href="https://www.freecodecamp.org/news/learn-typescript-with-react-handbook/" rel="noopener noreferrer" target="_blank">TypeScript
</a>
</li>
<li>
<a href="https://www.freecodecamp.org/news/learn-javascript-for-beginners/" rel="noopener noreferrer" target="_blank">JavaScript
</a>
</li>
<li>
<a href="https://www.freecodecamp.org/news/how-to-build-an-ai-chatbot-with-redis-python-and-gpt/" rel="noopener noreferrer" target="_blank">AI Chatbots
</a>
</li>
<li>
<a href="https://www.freecodecamp.org/news/command-line-for-beginners/" rel="noopener noreferrer" target="_blank">Command Line
</a>
</li>
<li>
<a href="https://www.freecodecamp.org/news/building-consuming-and-documenting-a-graphql-api/" rel="noopener noreferrer" target="_blank">GraphQL APIs
</a>
</li>
<li>
<a href="https://www.freecodecamp.org/news/complete-guide-to-css-transform-functions-and-properties/" rel="noopener noreferrer" target="_blank">CSS Transforms
</a>
</li>
<li>
<a href="https://www.freecodecamp.org/news/how-to-build-scalable-access-control-for-your-web-app/" rel="noopener noreferrer" target="_blank">Access Control
</a>
</li>
<li>
<a href="https://www.freecodecamp.org/news/rest-api-design-best-practices-build-a-rest-api/" rel="noopener noreferrer" target="_blank">REST API Design
</a>
</li>
<li>
<a href="https://www.freecodecamp.org/news/the-php-handbook/" rel="noopener noreferrer" target="_blank">PHP
</a>
</li>
<li>
<a href="https://www.freecodecamp.org/news/the-java-handbook/" rel="noopener noreferrer" target="_blank">Java
</a>
</li>
<li>
<a href="https://www.freecodecamp.org/news/learn-linux-for-beginners-book-basic-to-advanced/" rel="noopener noreferrer" target="_blank">Linux
</a>
</li>
<li>
<a href="https://www.freecodecamp.org/news/react-for-beginners-handbook/" rel="noopener noreferrer" target="_blank">React
</a>
</li>
<li>
<a href="https://www.freecodecamp.org/news/learn-continuous-integration-delivery-and-deployment/" rel="noopener noreferrer" target="_blank">CI/CD
</a>
</li>
<li>
<a href="https://www.freecodecamp.org/news/the-docker-handbook/" rel="noopener noreferrer" target="_blank">Docker
</a>
</li>
<li>
<a href="https://www.freecodecamp.org/news/learn-golang-handbook/" rel="noopener noreferrer" target="_blank">Golang
</a>
</li>
<li>
<a href="https://www.freecodecamp.org/news/the-python-handbook/" rel="noopener noreferrer" target="_blank">Python
</a>
</li>
<li>
<a href="https://www.freecodecamp.org/news/get-started-with-nodejs/" rel="noopener noreferrer" target="_blank">Node.js
</a>
</li>
<li>
<a href="https://www.freecodecamp.org/news/build-crud-operations-with-dotnet-core-handbook/" rel="noopener noreferrer" target="_blank">Todo APIs
</a>
</li>
<li>
<a href="https://www.freecodecamp.org/news/how-to-use-classes-in-javascript-handbook/" rel="noopener noreferrer" target="_blank">JavaScript Classes
</a>
</li>
<li>
<a href="https://www.freecodecamp.org/news/front-end-javascript-development-react-angular-vue-compared/" rel="noopener noreferrer" target="_blank">Front-End Libraries
</a>
</li>
<li>
<a href="https://www.freecodecamp.org/news/the-express-handbook/" rel="noopener noreferrer" target="_blank">Express and Node.js
</a>
</li>
<li>
<a href="https://www.freecodecamp.org/news/python-code-examples-sample-script-coding-tutorial-for-beginners/" rel="noopener noreferrer" target="_blank">Python Code Examples
</a>
</li>
<li>
<a href="https://www.freecodecamp.org/news/clustering-in-python-a-machine-learning-handbook/" rel="noopener noreferrer" target="_blank">Clustering in Python
</a>
</li>
<li>
<a href="https://www.freecodecamp.org/news/an-introduction-to-software-architecture-patterns/" rel="noopener noreferrer" target="_blank">Software Architecture
</a>
</li>
<li>
<a href="https://www.freecodecamp.org/news/what-is-programming-tutorial-for-beginners/" rel="noopener noreferrer" target="_blank">Programming Fundamentals
</a>
</li>
<li>
<a href="https://www.freecodecamp.org/news/learn-to-code-book/" rel="noopener noreferrer" target="_blank">Coding Career Preparation
</a>
</li>
<li>
<a href="https://www.freecodecamp.org/news/become-a-full-stack-developer-and-get-a-job/" rel="noopener noreferrer" target="_blank">Full-Stack Developer Guide
</a>
</li>
<li>
<a href="https://www.freecodecamp.org/news/learn-python-for-javascript-developers-handbook/" rel="noopener noreferrer" target="_blank">Python for JavaScript Devs
</a>
</li>
</ul>
<div class="spacer" style="padding: 15px 0;"></div>
<div>
<h2 id="mobile-app" class="col-header">
Mobile App
</h2>
<div class="min-h-[1px] px-[15px] md:w-2/3 md:ml-[16.6%]">
<ul aria-labelledby="mobile-app" class="mobile-app-container">
<li>
<a href="https://apps.apple.com/us/app/freecodecamp/id6446908151?itsct=apps_box_link&itscg=30200" rel="noopener noreferrer" target="_blank">
<img src="https://cdn.freecodecamp.org/platform/universal/apple-store-badge.svg" lang="en" alt="Download on the App Store">
</a>
</li>
<li>
<a href="https://play.google.com/store/apps/details?id=org.freecodecamp" rel="noopener noreferrer" target="_blank">
<img src="https://cdn.freecodecamp.org/platform/universal/google-play-badge.svg" lang="en" alt="Get it on Google Play">
</a>
</li>
</ul>
</div>
</div>
</div>
</div>
<div class="footer-bottom">
<h2 class="col-header" data-test-label="our-nonprofit">Our Charity</h2>
<div class="our-nonprofit"><a href="https://hashnode.com/" rel="noopener noreferrer" target="_blank" data-test-label="powered-by">
Publication powered by Hashnode
</a>
<a href="https://www.freecodecamp.org/news/about/" rel="noopener noreferrer" target="_blank" data-test-label="about">
About
</a>
<a href="https://www.linkedin.com/school/free-code-camp/people/" rel="noopener noreferrer" target="_blank" data-test-label="alumni">
Alumni Network
</a>
<a href="https://github.com/freeCodeCamp/" rel="noopener noreferrer" target="_blank" data-test-label="open-source">
Open Source
</a>
<a href="https://www.freecodecamp.org/news/shop/" rel="noopener noreferrer" target="_blank" data-test-label="shop">
Shop
</a>
<a href="https://www.freecodecamp.org/news/support/" rel="noopener noreferrer" target="_blank" data-test-label="support">
Support
</a>
<a href="https://www.freecodecamp.org/news/sponsors/" rel="noopener noreferrer" target="_blank" data-test-label="sponsors">
Sponsors
</a>
<a href="https://www.freecodecamp.org/news/academic-honesty-policy/" rel="noopener noreferrer" target="_blank" data-test-label="honesty">
Academic Honesty
</a>
<a href="https://www.freecodecamp.org/news/code-of-conduct/" rel="noopener noreferrer" target="_blank" data-test-label="coc">
Code of Conduct
</a>
<a href="https://www.freecodecamp.org/news/privacy-policy/" rel="noopener noreferrer" target="_blank" data-test-label="privacy">
Privacy Policy
</a>
<a href="https://www.freecodecamp.org/news/terms-of-service/" rel="noopener noreferrer" target="_blank" data-test-label="tos">
Terms of Service
</a>
<a href="https://www.freecodecamp.org/news/copyright-policy/" rel="noopener noreferrer" target="_blank" data-test-label="copyright">
Copyright Policy
</a>
</div>
</div>
</footer></div>
</body>
</html>

