<script type="module" src="https://unpkg.com/ionicons@7.1.0/dist/ionicons/ionicons.esm.js"></script> <script nomodule src="https://unpkg.com/ionicons@7.1.0/dist/ionicons/ionicons.js"></script> <div class="container"> <div class="icon-wrapper"> <ion-icon name="text-outline"></ion-icon> </div> <h1>Typewriter Effect</h1> <div class="typewriter-container"> <div class="typewriter-text"> <span id="text"></span><span class="cursor"></span> </div> </div> <div class="controls"> <button class="btn-primary" id="startBtn"> <ion-icon name="play-outline"></ion-icon> Start </button> <button class="btn-secondary" id="pauseBtn" disabled> <ion-icon name="pause-outline"></ion-icon> Pause </button> <button class="btn-secondary" id="resetBtn"> <ion-icon name="refresh-outline"></ion-icon> Reset </button> </div> <div class="speed-control"> <label for="speed">Speed:</label> <input type="range" id="speed" min="20" max="200" value="100" step="10"> <span class="speed-value" id="speedValue">100ms</span> </div> </div>
* { margin: 0; padding: 0; box-sizing: border-box; } body { font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, sans-serif; background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); min-height: 100vh; display: flex; align-items: center; justify-content: center; padding: 20px; } .container { max-width: 800px; width: 100%; background: white; border-radius: 16px; box-shadow: 0 20px 60px rgba(0,0,0,0.3); padding: 60px 40px; text-align: center; } .icon-wrapper { margin-bottom: 30px; } .icon-wrapper ion-icon { font-size: 48px; color: #667eea; } h1 { font-size: 32px; color: #1a202c; margin-bottom: 40px; font-weight: 600; } .typewriter-container { background: #f7fafc; border-radius: 12px; padding: 40px; min-height: 200px; display: flex; align-items: center; justify-content: center; margin-bottom: 30px; border: 2px solid #e2e8f0; } .typewriter-text { font-size: 24px; color: #2d3748; line-height: 1.6; font-weight: 500; } .cursor { display: inline-block; width: 3px; height: 28px; background: #667eea; margin-left: 2px; animation: blink 0.7s infinite; vertical-align: middle; } @keyframes blink { 0%, 50% { opacity: 1; } 51%, 100% { opacity: 0; } } .controls { display: flex; gap: 12px; justify-content: center; flex-wrap: wrap; } button { padding: 12px 24px; border: none; border-radius: 8px; font-size: 14px; font-weight: 500; cursor: pointer; transition: all 0.3s; display: inline-flex; align-items: center; gap: 8px; } .btn-primary { background: #667eea; color: white; } .btn-primary:hover { background: #5568d3; transform: translateY(-2px); box-shadow: 0 4px 12px rgba(102, 126, 234, 0.4); } .btn-secondary { background: #e2e8f0; color: #4a5568; } .btn-secondary:hover { background: #cbd5e0; transform: translateY(-2px); } button:disabled { opacity: 0.5; cursor: not-allowed; transform: none !important; } .speed-control { display: flex; align-items: center; gap: 12px; margin-top: 20px; justify-content: center; } .speed-control label { font-size: 14px; color: #4a5568; font-weight: 500; } input[type="range"] { width: 200px; height: 6px; border-radius: 3px; background: #e2e8f0; outline: none; -webkit-appearance: none; } input[type="range"]::-webkit-slider-thumb { -webkit-appearance: none; appearance: none; width: 18px; height: 18px; border-radius: 50%; background: #667eea; cursor: pointer; transition: all 0.3s; } input[type="range"]::-webkit-slider-thumb:hover { transform: scale(1.2); box-shadow: 0 0 0 8px rgba(102, 126, 234, 0.1); } input[type="range"]::-moz-range-thumb { width: 18px; height: 18px; border-radius: 50%; background: #667eea; cursor: pointer; border: none; } .speed-value { min-width: 60px; font-size: 14px; color: #667eea; font-weight: 600; }
const texts = [ "Welcome to the typewriter effect demo!", "This creates a realistic typing animation...", "Perfect for landing pages and hero sections.", "Watch as each character appears one by one." ]; let currentTextIndex = 0; let currentCharIndex = 0; let isTyping = false; let isPaused = false; let typingSpeed = 100; let timeoutId = null; const textElement = document.getElementById('text'); const startBtn = document.getElementById('startBtn'); const pauseBtn = document.getElementById('pauseBtn'); const resetBtn = document.getElementById('resetBtn'); const speedSlider = document.getElementById('speed'); const speedValue = document.getElementById('speedValue'); function typeWriter() { if (isPaused) return; const currentText = texts[currentTextIndex]; if (currentCharIndex < currentText.length) { textElement.textContent += currentText.charAt(currentCharIndex); currentCharIndex++; timeoutId = setTimeout(typeWriter, typingSpeed); } else { // Wait before moving to next text timeoutId = setTimeout(() => { currentTextIndex++; if (currentTextIndex < texts.length) { // Add line break and continue textElement.innerHTML += '<br><br>'; currentCharIndex = 0; typeWriter(); } else { // All texts completed isTyping = false; startBtn.disabled = true; pauseBtn.disabled = true; startBtn.innerHTML = '<ion-icon name="checkmark-outline"></ion-icon> Complete'; } }, 1000); } } function startTyping() { if (!isTyping) { isTyping = true; isPaused = false; startBtn.disabled = true; pauseBtn.disabled = false; startBtn.innerHTML = '<ion-icon name="play-outline"></ion-icon> Start'; pauseBtn.innerHTML = '<ion-icon name="pause-outline"></ion-icon> Pause'; typeWriter(); } else if (isPaused) { isPaused = false; pauseBtn.innerHTML = '<ion-icon name="pause-outline"></ion-icon> Pause'; typeWriter(); } } function pauseTyping() { if (isTyping && !isPaused) { isPaused = true; pauseBtn.innerHTML = '<ion-icon name="play-outline"></ion-icon> Resume'; if (timeoutId) { clearTimeout(timeoutId); } } else if (isPaused) { isPaused = false; pauseBtn.innerHTML = '<ion-icon name="pause-outline"></ion-icon> Pause'; typeWriter(); } } function resetTyping() { if (timeoutId) { clearTimeout(timeoutId); } textElement.textContent = ''; currentTextIndex = 0; currentCharIndex = 0; isTyping = false; isPaused = false; startBtn.disabled = false; pauseBtn.disabled = true; startBtn.innerHTML = '<ion-icon name="play-outline"></ion-icon> Start'; pauseBtn.innerHTML = '<ion-icon name="pause-outline"></ion-icon> Pause'; } startBtn.addEventListener('click', startTyping); pauseBtn.addEventListener('click', pauseTyping); resetBtn.addEventListener('click', resetTyping); speedSlider.addEventListener('input', (e) => { typingSpeed = parseInt(e.target.value); speedValue.textContent = `${typingSpeed}ms`; }); // Auto-start on load setTimeout(() => { startTyping(); }, 500);
Login to leave a comment
No comments yet. Be the first!
View Project
No comments yet. Be the first!