Toggle navigation
☰
Home
HTML
CSS
Scripting
Database
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Success & Error State Buttons</title> <style> /* Component: Stateful Feedback Buttons Description: Buttons that provide loading, success, and error feedback. */ :root { --state-btn-bg: #6c757d; --state-btn-text-color: #ffffff; --state-btn-success-bg: #28a745; --state-btn-error-bg: #dc3545; --state-btn-focus-outline: #007bff; } .state-btn-container-1 { font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif; display: flex; flex-direction: column; align-items: center; gap: 1.5rem; padding: 2rem; background-color: #f8f9fa; } .state-btn-1 { position: relative; display: flex; align-items: center; justify-content: center; width: 180px; height: 50px; padding: 0.9rem 1.8rem; font-size: 1.1rem; font-weight: 600; color: var(--state-btn-text-color); background-color: var(--state-btn-bg); border: none; border-radius: 8px; cursor: pointer; transition: background-color 0.2s ease-in-out; overflow: hidden; } /* Default state */ .state-btn-1 span, .state-btn-1 svg, .state-btn-1 .loader { position: absolute; transition: opacity 0.2s ease, transform 0.2s ease; } .state-btn-1 .icon-success, .state-btn-1 .icon-error, .state-btn-1 .loader { opacity: 0; transform: scale(0); } /* Loading State */ .state-btn-1.is-loading .btn-text { opacity: 0; transform: translateY(-10px); } .state-btn-1.is-loading .loader { opacity: 1; transform: scale(1); } /* Success State */ .state-btn-1.is-success { background-color: var(--state-btn-success-bg); } .state-btn-1.is-success .btn-text, .state-btn-1.is-success .loader { opacity: 0; } .state-btn-1.is-success .icon-success { opacity: 1; transform: scale(1.2); } /* Error State */ .state-btn-1.is-error { background-color: var(--state-btn-error-bg); } .state-btn-1.is-error .btn-text, .state-btn-1.is-error .loader { opacity: 0; } .state-btn-1.is-error .icon-error { opacity: 1; transform: scale(1.2); } /* Common Disabled Styles */ .state-btn-1.is-loading, .state-btn-1.is-success, .state-btn-1.is-error { cursor: wait; } .state-btn-1:focus-visible { outline: 3px solid var(--state-btn-focus-outline); outline-offset: 2px; } /* Loader Animation */ .loader { width: 24px; height: 24px; border: 3px solid rgba(255, 255, 255, 0.4); border-top-color: var(--state-btn-text-color); border-radius: 50%; animation: spin 1s linear infinite; } @keyframes spin { to { transform: rotate(360deg); } } .visually-hidden { position: absolute; width: 1px; height: 1px; margin: -1px; padding: 0; overflow: hidden; clip: rect(0, 0, 0, 0); border: 0; } </style> </head> <body> <div class="state-btn-container-1"> <button type="button" class="state-btn-1" id="btnSuccessDemo"> <span class="btn-text">Run Success</span> <div class="loader"></div> <svg class="icon-success" aria-hidden="true" height="24" width="24" viewBox="0 0 24 24" fill="currentColor"><path d="M9 16.17L4.83 12l-1.42 1.41L9 19 21 7l-1.41-1.41z"/></svg> </button> <button type="button" class="state-btn-1" id="btnErrorDemo"> <span class="btn-text">Run Error</span> <div class="loader"></div> <svg class="icon-error" aria-hidden="true" height="24" width="24" viewBox="0 0 24 24" fill="currentColor"><path d="M19 6.41L17.59 5 12 10.59 6.41 5 5 6.41 10.59 12 5 17.59 6.41 19 12 13.41 17.59 19 19 17.59 13.41 12z"/></svg> </button> <div id="statusAnnouncer" class="visually-hidden" aria-live="polite"></div> </div> <script> document.addEventListener('DOMContentLoaded', () => { const successBtn = document.getElementById('btnSuccessDemo'); const errorBtn = document.getElementById('btnErrorDemo'); const announcer = document.getElementById('statusAnnouncer'); const handleState = (btn, outcome) => { if (btn.disabled) return; btn.disabled = true; btn.classList.add('is-loading'); // 1. Loading phase setTimeout(() => { btn.classList.remove('is-loading'); if (outcome === 'success') { btn.classList.add('is-success'); announcer.textContent = "Operation successful."; } else { btn.classList.add('is-error'); announcer.textContent = "Operation failed. Please try again."; } // 2. Result phase setTimeout(() => { btn.classList.remove('is-success', 'is-error'); btn.disabled = false; announcer.textContent = ""; }, 2000); // How long to show success/error state }, 1500); // How long to show loading state }; successBtn.addEventListener('click', () => handleState(successBtn, 'success')); errorBtn.addEventListener('click', () => handleState(errorBtn, 'error')); }); </script> </body> </html>