$ cat docs/modals.md
updated Recently · 20 min read · published
Modals Introduction
Modal dialogs focus user attention on a specific task, form, or message without leaving the current page. This guide covers production-ready modal patterns in plain HTML/CSS, Tailwind CSS, and Bootstrap — including confirmation dialogs, forms, alerts, slide-out panels, sizing, and accessibility.
ℹ info
Always use role="dialog" and aria-modal="true" on the modal container, and bind the title with aria-labelledby . Trap focus inside the modal while it is open.
Confirmation Dialog
A centered confirmation dialog with backdrop blur, close controls, and destructive action buttons. Click the trigger to open, then close via the backdrop, Escape key, or action buttons.
confirmation-dialog HTML CSS JS Tailwind Bootstrap Live
Copy 1 <div class="modal-demo"> 2 <button class="open-btn" data-open="modal-confirm"> 3 Open Modal 4 </button> 5 <div class="modal-wrapper" id="modal-confirm"> 6 <div class="modal-backdrop" data-close> 7 </div> 8 <div class="modal" role="dialog" aria-modal="true" aria-labelledby="confirm-title"> 9 <div class="modal-header"> 10 <h3 id="confirm-title" class="modal-title"> 11 Confirm Action 12 </h3> 13 <button class="modal-close" data-close aria-label="Close"> 14 ✕ 15 </button> 16 </div> 17 <p class="modal-desc"> 18 Are you sure you want to delete this item? This action cannot be undone. All associated data will be permanently removed. 19 </p> 20 <div class="modal-footer"> 21 <button class="btn btn-secondary" data-close> 22 Cancel 23 </button> 24 <button class="btn btn-danger"> 25 Delete 26 </button> 27 </div> 28 </div> 29 </div> 30 </div>
Copy 1 .modal-demo { 2 position:relative; 3 min-height:260px; 4 display:flex; 5 align-items:center; 6 justify-content:center; 7 font-family:system-ui, 8 sans-serif; 9 background:#0A0A0A 10 } 11 .open-btn { 12 padding:12px 28px; 13 border-radius:8px; 14 font-size:14px; 15 font-weight:600; 16 background:#00FF41; 17 color:#0A0A0A; 18 border:none; 19 cursor:pointer; 20 transition:all .2s 21 } 22 .open-btn:hover { 23 transform:translateY(-2px); 24 box-shadow:0 8px 24px rgba(0, 25 0, 26 0, 27 .3) 28 } 29 .modal-wrapper { 30 position:absolute; 31 inset:0; 32 display:none; 33 align-items:center; 34 justify-content:center; 35 padding:24px; 36 z-index:50 37 } 38 .modal-wrapper.open { 39 display:flex 40 } 41 .modal-backdrop { 42 position:absolute; 43 inset:0; 44 background:rgba(0, 45 0, 46 0, 47 .65); 48 backdrop-filter:blur(4px) 49 } 50 .modal { 51 position:relative; 52 background:#111; 53 border:1px solid #2A2A3E; 54 border-radius:12px; 55 padding:0; 56 max-width:400px; 57 width:100%; 58 box-shadow:0 24px 64px rgba(0, 59 0, 60 0, 61 .5); 62 animation:modalIn .25s ease 63 } 64 @keyframes modalIn { 65 from { 66 opacity:0; 67 transform:scale(.95) translateY(10px) 68 } 69 to { 70 opacity:1; 71 transform:scale(1) translateY(0) 72 } 73 } 74 .modal-header { 75 display:flex; 76 align-items:center; 77 justify-content:space-between; 78 padding:20px 24px 0 79 } 80 .modal-title { 81 font-size:16px; 82 font-weight:700; 83 color:#E0E0E0; 84 margin:0 85 } 86 .modal-close { 87 width:28px; 88 height:28px; 89 border-radius:6px; 90 border:none; 91 background:transparent; 92 color:#808080; 93 cursor:pointer; 94 display:flex; 95 align-items:center; 96 justify-content:center; 97 font-size:14px; 98 transition:all .2s 99 } 100 .modal-close:hover { 101 background:rgba(255, 102 255, 103 255, 104 .05); 105 color:#E0E0E0 106 } 107 .modal-desc { 108 font-size:13px; 109 color:#808080; 110 margin:12px 24px 20px; 111 line-height:1.5 112 } 113 .modal-footer { 114 display:flex; 115 gap:8px; 116 justify-content:flex-end; 117 padding:16px 24px; 118 border-top:1px solid #222 119 } 120 .btn { 121 padding:8px 16px; 122 border-radius:6px; 123 font-size:12px; 124 font-weight:600; 125 font-family:inherit; 126 cursor:pointer; 127 border:none; 128 transition:all .2s 129 } 130 .btn-secondary { 131 background:transparent; 132 color:#A0A0A0; 133 border:1px solid #2A2A3E 134 } 135 .btn-secondary:hover { 136 background:rgba(255, 137 255, 138 255, 139 .05); 140 color:#E0E0E0; 141 border-color:#3A3A4E 142 } 143 .btn-danger { 144 background:#EF4444; 145 color:#fff 146 } 147 .btn-danger:hover { 148 background:#DC2626 149 }
untitled.js wrap JavaScript
Copy 1 const open=document.querySelector('[data-open="modal-confirm"]');const wrap=document.getElementById('modal-confirm');const close=()=>wrap.classList.remove('open');open.addEventListener('click',()=>wrap.classList.add('open'));wrap.querySelectorAll('[data-close]').forEach(el=>el.addEventListener('click',close));document.addEventListener('keydown',e=>{if(e.key==='Escape'&&wrap.classList.contains('open'))close()})
Copy 1 <div class="relative min-h-[260px] flex items-center justify-center bg-[#0A0A0A] font-sans"> 2 <button data-open="modal-confirm" class="px-7 py-3 rounded-lg text-sm font-semibold bg-[#00FF41] text-[#0A0A0A] hover:bg-[#00E63A] hover:-translate-y-0.5 hover:shadow-[0_8px_24px_rgba(0,0,0,0.3)] transition-all"> 3 Open Modal 4 </button> 5 <div id="modal-confirm" class="hidden absolute inset-0 items-center justify-center p-6 z-50"> 6 <div data-close class="absolute inset-0 bg-black/65 backdrop-blur-sm"> 7 </div> 8 <div role="dialog" aria-modal="true" aria-labelledby="confirm-title" class="relative bg-[#111] border border-[#2A2A3E] rounded-xl max-w-[400px] w-full shadow-[0_24px_64px_rgba(0,0,0,0.5)] animate-[modalIn_0.25s_ease]"> 9 <div class="flex items-center justify-between px-6 pt-5"> 10 <h3 id="confirm-title" class="text-base font-bold text-[#E0E0E0]"> 11 Confirm Action 12 </h3> 13 <button data-close aria-label="Close" class="w-7 h-7 rounded-md border-0 bg-transparent text-[#808080] hover:bg-white/5 hover:text-[#E0E0E0] flex items-center justify-center text-sm transition-all"> 14 ✕ 15 </button> 16 </div> 17 <p class="text-[13px] text-[#808080] mx-6 mt-3 mb-5 leading-relaxed"> 18 Are you sure you want to delete this item? This action cannot be undone. 19 </p> 20 <div class="flex gap-2 justify-end px-6 py-4 border-t border-[#222]"> 21 <button data-close class="px-4 py-2 rounded-md text-xs font-semibold bg-transparent text-[#A0A0A0] border border-[#2A2A3E] hover:bg-white/5 hover:text-[#E0E0E0] hover:border-[#3A3A4E] transition-all"> 22 Cancel 23 </button> 24 <button class="px-4 py-2 rounded-md text-xs font-semibold bg-[#EF4444] text-white hover:bg-[#DC2626] transition-all"> 25 Delete 26 </button> 27 </div> 28 </div> 29 </div> 30 <style> 31 @keyframes modalIn{from{opacity:0;transform:scale(.95) translateY(10px)}to{opacity:1;transform:scale(1) translateY(0)}} 32 </style> 33 </div>
Copy 1 <div class="d-flex align-items-center justify-content-center p-4" style="min-height:260px;background:#0A0A0A"> 2 <button class="btn fw-semibold" data-bs-toggle="modal" data-bs-target="#modalConfirm" style="--bs-btn-bg:#00FF41;--bs-btn-color:#0A0A0A;--bs-btn-border-color:#00FF41;--bs-btn-hover-bg:#00E63A;--bs-btn-hover-border-color:#00E63A"> 3 Open Modal 4 </button> 5 <div class="modal fade" id="modalConfirm" tabindex="-1" aria-labelledby="confirm-title" aria-hidden="true"> 6 <div class="modal-dialog modal-dialog-centered"> 7 <div class="modal-content" style="background:#111;border:1px solid #2A2A3E"> 8 <div class="modal-header border-secondary"> 9 <h5 class="modal-title fs-6 fw-bold" style="color:#E0E0E0" id="confirm-title"> 10 Confirm Action 11 </h5> 12 <button type="button" class="btn-close btn-close-white" data-bs-dismiss="modal" aria-label="Close"> 13 </button> 14 </div> 15 <div class="modal-body"> 16 <p class="text-secondary mb-0"> 17 Are you sure you want to delete this item? This action cannot be undone. 18 </p> 19 </div> 20 <div class="modal-footer border-secondary"> 21 <button type="button" class="btn btn-outline-secondary" data-bs-dismiss="modal"> 22 Cancel 23 </button> 24 <button type="button" class="btn btn-danger"> 25 Delete 26 </button> 27 </div> 28 </div> 29 </div> 30 </div> 31 </div>
preview
Alert & Status Modal
Status modals communicate the result of an action. Use an inline SVG icon, a concise message, and a single primary action to dismiss.
status-modal HTML CSS JS Tailwind Bootstrap Live
Copy 1 <div class="modal-demo"> 2 <button class="open-btn" data-open="modal-status"> 3 Show Status 4 </button> 5 <div class="modal-wrapper" id="modal-status"> 6 <div class="modal-backdrop" data-close> 7 </div> 8 <div class="modal alert-modal" role="dialog" aria-modal="true" aria-labelledby="status-title"> 9 <div class="alert-icon"> 10 <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" width="32" height="32"> 11 <path d="M22 11.08V12a10 10 0 1 1-5.93-9.14"/> 12 <polyline points="22 4 12 14.01 9 11.01"/> 13 </svg> 14 </div> 15 <h3 id="status-title" class="modal-title centered"> 16 Payment Successful 17 </h3> 18 <p class="modal-desc centered"> 19 Your transaction has been processed. A receipt has been sent to your email. 20 </p> 21 <div class="modal-footer centered"> 22 <button class="btn btn-primary" data-close> 23 Done 24 </button> 25 </div> 26 </div> 27 </div> 28 </div>
Copy 1 .modal-demo { 2 position:relative; 3 min-height:280px; 4 display:flex; 5 align-items:center; 6 justify-content:center; 7 font-family:system-ui, 8 sans-serif; 9 background:#0A0A0A 10 } 11 .open-btn { 12 padding:12px 28px; 13 border-radius:8px; 14 font-size:14px; 15 font-weight:600; 16 background:#00FF41; 17 color:#0A0A0A; 18 border:none; 19 cursor:pointer; 20 transition:all .2s 21 } 22 .open-btn:hover { 23 transform:translateY(-2px); 24 box-shadow:0 8px 24px rgba(0, 25 0, 26 0, 27 .3) 28 } 29 .modal-wrapper { 30 position:absolute; 31 inset:0; 32 display:none; 33 align-items:center; 34 justify-content:center; 35 padding:24px; 36 z-index:50 37 } 38 .modal-wrapper.open { 39 display:flex 40 } 41 .modal-backdrop { 42 position:absolute; 43 inset:0; 44 background:rgba(0, 45 0, 46 0, 47 .65); 48 backdrop-filter:blur(4px) 49 } 50 .modal { 51 position:relative; 52 background:#111; 53 border:1px solid #2A2A3E; 54 border-radius:12px; 55 padding:0; 56 max-width:360px; 57 width:100%; 58 box-shadow:0 24px 64px rgba(0, 59 0, 60 0, 61 .5); 62 animation:modalIn .25s ease 63 } 64 @keyframes modalIn { 65 from { 66 opacity:0; 67 transform:scale(.95) translateY(10px) 68 } 69 to { 70 opacity:1; 71 transform:scale(1) translateY(0) 72 } 73 } 74 .alert-modal { 75 padding:28px 24px; 76 text-align:center 77 } 78 .alert-icon { 79 width:56px; 80 height:56px; 81 border-radius:50%; 82 background:rgba(0, 83 255, 84 65, 85 .1); 86 color:#00FF41; 87 display:flex; 88 align-items:center; 89 justify-content:center; 90 margin:0 auto 16px 91 } 92 .modal-title { 93 font-size:16px; 94 font-weight:700; 95 color:#E0E0E0; 96 margin:0 97 } 98 .modal-title.centered { 99 text-align:center 100 } 101 .modal-desc { 102 font-size:13px; 103 color:#808080; 104 margin:12px 0 20px; 105 line-height:1.5 106 } 107 .modal-desc.centered { 108 text-align:center 109 } 110 .modal-footer { 111 display:flex; 112 gap:8px; 113 justify-content:flex-end; 114 padding:0 115 } 116 .modal-footer.centered { 117 justify-content:center 118 } 119 .btn { 120 padding:10px 20px; 121 border-radius:6px; 122 font-size:13px; 123 font-weight:600; 124 font-family:inherit; 125 cursor:pointer; 126 border:none; 127 transition:all .2s 128 } 129 .btn-primary { 130 background:#00FF41; 131 color:#0A0A0A 132 } 133 .btn-primary:hover { 134 background:#00E63A 135 }
untitled.js wrap JavaScript
Copy 1 const sOpen=document.querySelector('[data-open="modal-status"]');const sWrap=document.getElementById('modal-status');const sClose=()=>sWrap.classList.remove('open');sOpen.addEventListener('click',()=>sWrap.classList.add('open'));sWrap.querySelectorAll('[data-close]').forEach(el=>el.addEventListener('click',sClose));document.addEventListener('keydown',e=>{if(e.key==='Escape'&&sWrap.classList.contains('open'))sClose()})
Copy 1 <div class="relative min-h-[280px] flex items-center justify-center bg-[#0A0A0A] font-sans"> 2 <button data-open="modal-status" class="px-7 py-3 rounded-lg text-sm font-semibold bg-[#00FF41] text-[#0A0A0A] hover:bg-[#00E63A] hover:-translate-y-0.5 hover:shadow-[0_8px_24px_rgba(0,0,0,0.3)] transition-all"> 3 Show Status 4 </button> 5 <div id="modal-status" class="hidden absolute inset-0 items-center justify-center p-6 z-50"> 6 <div data-close class="absolute inset-0 bg-black/65 backdrop-blur-sm"> 7 </div> 8 <div role="dialog" aria-modal="true" aria-labelledby="status-title" class="relative bg-[#111] border border-[#2A2A3E] rounded-xl max-w-[360px] w-full shadow-[0_24px_64px_rgba(0,0,0,0.5)] animate-[modalIn_0.25s_ease] p-7 text-center"> 9 <div class="w-14 h-14 rounded-full bg-[rgba(0,255,65,0.1)] text-[#00FF41] flex items-center justify-center mx-auto mb-4"> 10 <svg class="w-8 h-8" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"> 11 <path d="M22 11.08V12a10 10 0 1 1-5.93-9.14"/> 12 <polyline points="22 4 12 14.01 9 11.01"/> 13 </svg> 14 </div> 15 <h3 id="status-title" class="text-base font-bold text-[#E0E0E0]"> 16 Payment Successful 17 </h3> 18 <p class="text-[13px] text-[#808080] mt-3 mb-5 leading-relaxed"> 19 Your transaction has been processed. A receipt has been sent to your email. 20 </p> 21 <button data-close class="px-5 py-2.5 rounded-md text-[13px] font-semibold bg-[#00FF41] text-[#0A0A0A] hover:bg-[#00E63A] transition-all"> 22 Done 23 </button> 24 </div> 25 </div> 26 <style> 27 @keyframes modalIn{from{opacity:0;transform:scale(.95) translateY(10px)}to{opacity:1;transform:scale(1) translateY(0)}} 28 </style> 29 </div>
Copy 1 <div class="d-flex align-items-center justify-content-center p-4" style="min-height:280px;background:#0A0A0A"> 2 <button class="btn fw-semibold" data-bs-toggle="modal" data-bs-target="#modalStatus" style="--bs-btn-bg:#00FF41;--bs-btn-color:#0A0A0A;--bs-btn-border-color:#00FF41;--bs-btn-hover-bg:#00E63A;--bs-btn-hover-border-color:#00E63A"> 3 Show Status 4 </button> 5 <div class="modal fade" id="modalStatus" tabindex="-1" aria-labelledby="status-title" aria-hidden="true"> 6 <div class="modal-dialog modal-dialog-centered"> 7 <div class="modal-content text-center p-4" style="background:#111;border:1px solid #2A2A3E"> 8 <div class="d-flex align-items-center justify-content-center mx-auto mb-3 rounded-circle" style="width:56px;height:56px;background:rgba(0,255,65,.1);color:#00FF41"> 9 <svg width="32" height="32" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"> 10 <path d="M22 11.08V12a10 10 0 1 1-5.93-9.14"/> 11 <polyline points="22 4 12 14.01 9 11.01"/> 12 </svg> 13 </div> 14 <h5 class="modal-title fs-6 fw-bold" style="color:#E0E0E0" id="status-title"> 15 Payment Successful 16 </h5> 17 <p class="text-secondary mt-3 mb-4"> 18 Your transaction has been processed. A receipt has been sent to your email. 19 </p> 20 <button type="button" class="btn fw-semibold" data-bs-dismiss="modal" style="--bs-btn-bg:#00FF41;--bs-btn-color:#0A0A0A;--bs-btn-border-color:#00FF41;--bs-btn-hover-bg:#00E63A"> 21 Done 22 </button> 23 </div> 24 </div> 25 </div> 26 </div>
preview
Slide-Out Panel
Slide-out panels enter from an edge and work well for detail views, settings, or shopping carts. Add a backdrop and close on Escape or backdrop click for a native feel.
slide-panel HTML CSS JS Tailwind Bootstrap Live
Copy 1 <div class="panel-demo"> 2 <button class="open-btn" data-open="panel-settings"> 3 Open Settings 4 </button> 5 <div class="panel-wrapper" id="panel-settings"> 6 <div class="panel-backdrop" data-close> 7 </div> 8 <div class="panel" role="dialog" aria-modal="true" aria-labelledby="panel-title"> 9 <div class="panel-header"> 10 <h3 id="panel-title" class="panel-title"> 11 Settings 12 </h3> 13 <button class="panel-close" data-close aria-label="Close panel"> 14 ✕ 15 </button> 16 </div> 17 <div class="panel-body"> 18 <div class="panel-row"> 19 <span> 20 Dark mode 21 </span> 22 <input type="checkbox" checked /> 23 </div> 24 <div class="panel-row"> 25 <span> 26 Notifications 27 </span> 28 <input type="checkbox" checked /> 29 </div> 30 <div class="panel-row"> 31 <span> 32 Auto-save 33 </span> 34 <input type="checkbox" /> 35 </div> 36 </div> 37 </div> 38 </div> 39 </div>
Copy 1 .panel-demo { 2 position:relative; 3 min-height:300px; 4 overflow:hidden; 5 display:flex; 6 align-items:center; 7 justify-content:center; 8 font-family:system-ui, 9 sans-serif; 10 background:#0A0A0A 11 } 12 .open-btn { 13 padding:12px 28px; 14 border-radius:8px; 15 font-size:14px; 16 font-weight:600; 17 background:#00FF41; 18 color:#0A0A0A; 19 border:none; 20 cursor:pointer; 21 transition:all .2s 22 } 23 .open-btn:hover { 24 transform:translateY(-2px); 25 box-shadow:0 8px 24px rgba(0, 26 0, 27 0, 28 .3) 29 } 30 .panel-wrapper { 31 position:absolute; 32 inset:0; 33 display:none; 34 z-index:50 35 } 36 .panel-wrapper.open { 37 display:block 38 } 39 .panel-backdrop { 40 position:absolute; 41 inset:0; 42 background:rgba(0, 43 0, 44 0, 45 .5) 46 } 47 .panel { 48 position:absolute; 49 top:0; 50 right:0; 51 bottom:0; 52 width:280px; 53 background:#111; 54 border-left:1px solid #2A2A3E; 55 display:flex; 56 flex-direction:column; 57 box-shadow:-8px 0 32px rgba(0, 58 0, 59 0, 60 .3); 61 animation:slideIn .3s ease 62 } 63 @keyframes slideIn { 64 from { 65 transform:translateX(100%) 66 } 67 to { 68 transform:translateX(0) 69 } 70 } 71 .panel-header { 72 padding:20px; 73 border-bottom:1px solid #222; 74 display:flex; 75 align-items:center; 76 justify-content:space-between 77 } 78 .panel-title { 79 font-size:15px; 80 font-weight:600; 81 color:#E0E0E0; 82 margin:0 83 } 84 .panel-close { 85 width:28px; 86 height:28px; 87 border-radius:6px; 88 border:none; 89 background:transparent; 90 color:#808080; 91 cursor:pointer; 92 display:flex; 93 align-items:center; 94 justify-content:center; 95 font-size:14px; 96 transition:all .2s 97 } 98 .panel-close:hover { 99 background:rgba(255, 100 255, 101 255, 102 .05); 103 color:#E0E0E0 104 } 105 .panel-body { 106 padding:16px 20px; 107 flex:1; 108 overflow-y:auto 109 } 110 .panel-row { 111 display:flex; 112 align-items:center; 113 justify-content:space-between; 114 padding:12px 0; 115 border-bottom:1px solid #222; 116 font-size:13px; 117 color:#A0A0A0 118 } 119 .panel-row input { 120 width:18px; 121 height:18px; 122 accent-color:#00FF41; 123 cursor:pointer 124 }
untitled.js wrap JavaScript
Copy 1 const pOpen=document.querySelector('[data-open="panel-settings"]');const pWrap=document.getElementById('panel-settings');const pClose=()=>pWrap.classList.remove('open');pOpen.addEventListener('click',()=>pWrap.classList.add('open'));pWrap.querySelectorAll('[data-close]').forEach(el=>el.addEventListener('click',pClose));document.addEventListener('keydown',e=>{if(e.key==='Escape'&&pWrap.classList.contains('open'))pClose()})
Copy 1 <div class="relative min-h-[300px] overflow-hidden flex items-center justify-center bg-[#0A0A0A] font-sans"> 2 <button data-open="panel-settings" class="px-7 py-3 rounded-lg text-sm font-semibold bg-[#00FF41] text-[#0A0A0A] hover:bg-[#00E63A] hover:-translate-y-0.5 hover:shadow-[0_8px_24px_rgba(0,0,0,0.3)] transition-all"> 3 Open Settings 4 </button> 5 <div id="panel-settings" class="hidden absolute inset-0 z-50"> 6 <div data-close class="absolute inset-0 bg-black/50"> 7 </div> 8 <div role="dialog" aria-modal="true" aria-labelledby="panel-title" class="absolute top-0 right-0 bottom-0 w-[280px] bg-[#111] border-l border-[#2A2A3E] flex flex-col shadow-[-8px_0_32px_rgba(0,0,0,0.3)] animate-[slideIn_0.3s_ease]"> 9 <div class="flex items-center justify-between p-5 border-b border-[#222]"> 10 <h3 id="panel-title" class="text-[15px] font-semibold text-[#E0E0E0]"> 11 Settings 12 </h3> 13 <button data-close aria-label="Close panel" class="w-7 h-7 rounded-md border-0 bg-transparent text-[#808080] hover:bg-white/5 hover:text-[#E0E0E0] flex items-center justify-center text-sm transition-all"> 14 ✕ 15 </button> 16 </div> 17 <div class="px-5 py-4 flex-1 overflow-y-auto"> 18 <label class="flex items-center justify-between py-3 border-b border-[#222] text-[13px] text-[#A0A0A0] cursor-pointer"> 19 Dark mode 20 <input type="checkbox" checked class="w-[18px] h-[18px] accent-[#00FF41]" /> 21 </label> 22 <label class="flex items-center justify-between py-3 border-b border-[#222] text-[13px] text-[#A0A0A0] cursor-pointer"> 23 Notifications 24 <input type="checkbox" checked class="w-[18px] h-[18px] accent-[#00FF41]" /> 25 </label> 26 <label class="flex items-center justify-between py-3 border-b border-[#222] text-[13px] text-[#A0A0A0] cursor-pointer"> 27 Auto-save 28 <input type="checkbox" class="w-[18px] h-[18px] accent-[#00FF41]" /> 29 </label> 30 </div> 31 </div> 32 </div> 33 <style> 34 @keyframes slideIn{from{transform:translateX(100%)}to{transform:translateX(0)}} 35 </style> 36 </div>
Copy 1 <div class="d-flex align-items-center justify-content-center p-4" style="min-height:300px;background:#0A0A0A"> 2 <button class="btn fw-semibold" data-bs-toggle="offcanvas" data-bs-target="#offcanvasSettings" aria-controls="offcanvasSettings" style="--bs-btn-bg:#00FF41;--bs-btn-color:#0A0A0A;--bs-btn-border-color:#00FF41;--bs-btn-hover-bg:#00E63A;--bs-btn-hover-border-color:#00E63A"> 3 Open Settings 4 </button> 5 <div class="offcanvas offcanvas-end" tabindex="-1" id="offcanvasSettings" aria-labelledby="panel-title" style="background:#111;border-left:1px solid #2A2A3E;width:280px"> 6 <div class="offcanvas-header border-secondary"> 7 <h5 class="offcanvas-title fs-6 fw-semibold" style="color:#E0E0E0" id="panel-title"> 8 Settings 9 </h5> 10 <button type="button" class="btn-close btn-close-white" data-bs-dismiss="offcanvas" aria-label="Close"> 11 </button> 12 </div> 13 <div class="offcanvas-body"> 14 <label class="d-flex align-items-center justify-content-between py-3 border-bottom border-secondary text-secondary" style="font-size:13px"> 15 Dark mode 16 <input type="checkbox" checked class="form-check-input" style="width:18px;height:18px" /> 17 </label> 18 <label class="d-flex align-items-center justify-content-between py-3 border-bottom border-secondary text-secondary" style="font-size:13px"> 19 Notifications 20 <input type="checkbox" checked class="form-check-input" style="width:18px;height:18px" /> 21 </label> 22 <label class="d-flex align-items-center justify-content-between py-3 border-bottom border-secondary text-secondary" style="font-size:13px"> 23 Auto-save 24 <input type="checkbox" class="form-check-input" style="width:18px;height:18px" /> 25 </label> 26 </div> 27 </div> 28 </div>
preview
Modal Sizes
Match the modal width to the content. Small modals work for confirmations, large modals for rich content like tables or media previews.
modal-sizes HTML CSS JS Tailwind Bootstrap Live
Copy 1 <div class="sizes-demo"> 2 <button class="open-btn" data-open="modal-size"> 3 Open Large Modal 4 </button> 5 <div class="modal-wrapper" id="modal-size"> 6 <div class="modal-backdrop" data-close> 7 </div> 8 <div class="modal modal-lg" role="dialog" aria-modal="true" aria-labelledby="size-title"> 9 <div class="modal-header"> 10 <h3 id="size-title" class="modal-title"> 11 Deployment Log 12 </h3> 13 <button class="modal-close" data-close aria-label="Close"> 14 ✕ 15 </button> 16 </div> 17 <div class="modal-body"> 18 <p class="modal-desc no-margin"> 19 Build 20 <span class="mono"> 21 #4821 22 </span> 23 completed successfully. Review the output below before promoting to production. 24 </p> 25 <div class="log-block"> 26 <div class="log-line"> 27 <span class="log-time"> 28 12:04:32 29 </span> 30 <span class="log-msg"> 31 Starting build... 32 </span> 33 </div> 34 <div class="log-line"> 35 <span class="log-time"> 36 12:04:45 37 </span> 38 <span class="log-msg"> 39 Compiling modules 40 </span> 41 </div> 42 <div class="log-line"> 43 <span class="log-time"> 44 12:05:01 45 </span> 46 <span class="log-msg success"> 47 Build succeeded in 29s 48 </span> 49 </div> 50 </div> 51 </div> 52 <div class="modal-footer"> 53 <button class="btn btn-secondary" data-close> 54 Close 55 </button> 56 <button class="btn btn-primary"> 57 Deploy 58 </button> 59 </div> 60 </div> 61 </div> 62 </div>
Copy 1 .sizes-demo { 2 position:relative; 3 min-height:320px; 4 display:flex; 5 align-items:center; 6 justify-content:center; 7 font-family:system-ui, 8 sans-serif; 9 background:#0A0A0A 10 } 11 .open-btn { 12 padding:12px 28px; 13 border-radius:8px; 14 font-size:14px; 15 font-weight:600; 16 background:#00FF41; 17 color:#0A0A0A; 18 border:none; 19 cursor:pointer; 20 transition:all .2s 21 } 22 .open-btn:hover { 23 transform:translateY(-2px); 24 box-shadow:0 8px 24px rgba(0, 25 0, 26 0, 27 .3) 28 } 29 .modal-wrapper { 30 position:absolute; 31 inset:0; 32 display:none; 33 align-items:center; 34 justify-content:center; 35 padding:24px; 36 z-index:50 37 } 38 .modal-wrapper.open { 39 display:flex 40 } 41 .modal-backdrop { 42 position:absolute; 43 inset:0; 44 background:rgba(0, 45 0, 46 0, 47 .65); 48 backdrop-filter:blur(4px) 49 } 50 .modal { 51 position:relative; 52 background:#111; 53 border:1px solid #2A2A3E; 54 border-radius:12px; 55 padding:0; 56 max-width:400px; 57 width:100%; 58 box-shadow:0 24px 64px rgba(0, 59 0, 60 0, 61 .5); 62 animation:modalIn .25s ease 63 } 64 @keyframes modalIn { 65 from { 66 opacity:0; 67 transform:scale(.95) translateY(10px) 68 } 69 to { 70 opacity:1; 71 transform:scale(1) translateY(0) 72 } 73 } 74 .modal.modal-lg { 75 max-width:560px 76 } 77 .modal-header { 78 display:flex; 79 align-items:center; 80 justify-content:space-between; 81 padding:20px 24px 0 82 } 83 .modal-title { 84 font-size:16px; 85 font-weight:700; 86 color:#E0E0E0; 87 margin:0 88 } 89 .modal-close { 90 width:28px; 91 height:28px; 92 border-radius:6px; 93 border:none; 94 background:transparent; 95 color:#808080; 96 cursor:pointer; 97 display:flex; 98 align-items:center; 99 justify-content:center; 100 font-size:14px; 101 transition:all .2s 102 } 103 .modal-close:hover { 104 background:rgba(255, 105 255, 106 255, 107 .05); 108 color:#E0E0E0 109 } 110 .modal-body { 111 padding:0 24px 112 } 113 .modal-desc { 114 font-size:13px; 115 color:#808080; 116 line-height:1.5; 117 margin:0 0 16px 118 } 119 .modal-desc.no-margin { 120 margin-bottom:0 121 } 122 .log-block { 123 background:#0A0A0A; 124 border:1px solid #222; 125 border-radius:8px; 126 padding:14px; 127 margin:16px 0 20px; 128 font-family:ui-monospace, 129 SFMono-Regular, 130 Menlo, 131 monospace 132 } 133 .log-line { 134 display:flex; 135 gap:12px; 136 font-size:12px; 137 color:#A0A0A0; 138 line-height:1.8 139 } 140 .log-time { 141 color:#666; 142 min-width:64px 143 } 144 .log-msg.success { 145 color:#00FF41 146 } 147 .mono { 148 font-family:ui-monospace, 149 SFMono-Regular, 150 Menlo, 151 monospace; 152 color:#00FF41 153 } 154 .modal-footer { 155 display:flex; 156 gap:8px; 157 justify-content:flex-end; 158 padding:16px 24px; 159 border-top:1px solid #222 160 } 161 .btn { 162 padding:8px 16px; 163 border-radius:6px; 164 font-size:12px; 165 font-weight:600; 166 font-family:inherit; 167 cursor:pointer; 168 border:none; 169 transition:all .2s 170 } 171 .btn-secondary { 172 background:transparent; 173 color:#A0A0A0; 174 border:1px solid #2A2A3E 175 } 176 .btn-secondary:hover { 177 background:rgba(255, 178 255, 179 255, 180 .05); 181 color:#E0E0E0; 182 border-color:#3A3A4E 183 } 184 .btn-primary { 185 background:#00FF41; 186 color:#0A0A0A 187 } 188 .btn-primary:hover { 189 background:#00E63A 190 }
untitled.js wrap JavaScript
Copy 1 const zOpen=document.querySelector('[data-open="modal-size"]');const zWrap=document.getElementById('modal-size');const zClose=()=>zWrap.classList.remove('open');zOpen.addEventListener('click',()=>zWrap.classList.add('open'));zWrap.querySelectorAll('[data-close]').forEach(el=>el.addEventListener('click',zClose));document.addEventListener('keydown',e=>{if(e.key==='Escape'&&zWrap.classList.contains('open'))zClose()})
Copy 1 <div class="relative min-h-[320px] flex items-center justify-center bg-[#0A0A0A] font-sans"> 2 <button data-open="modal-size" class="px-7 py-3 rounded-lg text-sm font-semibold bg-[#00FF41] text-[#0A0A0A] hover:bg-[#00E63A] hover:-translate-y-0.5 hover:shadow-[0_8px_24px_rgba(0,0,0,0.3)] transition-all"> 3 Open Large Modal 4 </button> 5 <div id="modal-size" class="hidden absolute inset-0 items-center justify-center p-6 z-50"> 6 <div data-close class="absolute inset-0 bg-black/65 backdrop-blur-sm"> 7 </div> 8 <div role="dialog" aria-modal="true" aria-labelledby="size-title" class="relative bg-[#111] border border-[#2A2A3E] rounded-xl max-w-[560px] w-full shadow-[0_24px_64px_rgba(0,0,0,0.5)] animate-[modalIn_0.25s_ease]"> 9 <div class="flex items-center justify-between px-6 pt-5"> 10 <h3 id="size-title" class="text-base font-bold text-[#E0E0E0]"> 11 Deployment Log 12 </h3> 13 <button data-close aria-label="Close" class="w-7 h-7 rounded-md border-0 bg-transparent text-[#808080] hover:bg-white/5 hover:text-[#E0E0E0] flex items-center justify-center text-sm transition-all"> 14 ✕ 15 </button> 16 </div> 17 <div class="px-6"> 18 <p class="text-[13px] text-[#808080] leading-relaxed"> 19 Build 20 <span class="font-mono text-[#00FF41]"> 21 #4821 22 </span> 23 completed successfully. Review the output below before promoting to production. 24 </p> 25 <div class="bg-[#0A0A0A] border border-[#222] rounded-lg p-3.5 my-4 font-mono"> 26 <div class="flex gap-3 text-xs text-[#A0A0A0] leading-7"> 27 <span class="text-[#666] min-w-[64px]"> 28 12:04:32 29 </span> 30 <span> 31 Starting build... 32 </span> 33 </div> 34 <div class="flex gap-3 text-xs text-[#A0A0A0] leading-7"> 35 <span class="text-[#666] min-w-[64px]"> 36 12:04:45 37 </span> 38 <span> 39 Compiling modules 40 </span> 41 </div> 42 <div class="flex gap-3 text-xs leading-7"> 43 <span class="text-[#666] min-w-[64px]"> 44 12:05:01 45 </span> 46 <span class="text-[#00FF41]"> 47 Build succeeded in 29s 48 </span> 49 </div> 50 </div> 51 </div> 52 <div class="flex gap-2 justify-end px-6 py-4 border-t border-[#222]"> 53 <button data-close class="px-4 py-2 rounded-md text-xs font-semibold bg-transparent text-[#A0A0A0] border border-[#2A2A3E] hover:bg-white/5 hover:text-[#E0E0E0] hover:border-[#3A3A4E] transition-all"> 54 Close 55 </button> 56 <button class="px-4 py-2 rounded-md text-xs font-semibold bg-[#00FF41] text-[#0A0A0A] hover:bg-[#00E63A] transition-all"> 57 Deploy 58 </button> 59 </div> 60 </div> 61 </div> 62 <style> 63 @keyframes modalIn{from{opacity:0;transform:scale(.95) translateY(10px)}to{opacity:1;transform:scale(1) translateY(0)}} 64 </style> 65 </div>
Copy 1 <div class="d-flex align-items-center justify-content-center p-4" style="min-height:320px;background:#0A0A0A"> 2 <button class="btn fw-semibold" data-bs-toggle="modal" data-bs-target="#modalSize" style="--bs-btn-bg:#00FF41;--bs-btn-color:#0A0A0A;--bs-btn-border-color:#00FF41;--bs-btn-hover-bg:#00E63A;--bs-btn-hover-border-color:#00E63A"> 3 Open Large Modal 4 </button> 5 <div class="modal fade" id="modalSize" tabindex="-1" aria-labelledby="size-title" aria-hidden="true"> 6 <div class="modal-dialog modal-lg modal-dialog-centered"> 7 <div class="modal-content" style="background:#111;border:1px solid #2A2A3E"> 8 <div class="modal-header border-secondary"> 9 <h5 class="modal-title fs-6 fw-bold" style="color:#E0E0E0" id="size-title"> 10 Deployment Log 11 </h5> 12 <button type="button" class="btn-close btn-close-white" data-bs-dismiss="modal" aria-label="Close"> 13 </button> 14 </div> 15 <div class="modal-body"> 16 <p class="text-secondary"> 17 Build 18 <span class="font-monospace" style="color:#00FF41"> 19 #4821 20 </span> 21 completed successfully. Review the output below before promoting to production. 22 </p> 23 <div class="p-3 rounded border-secondary font-monospace" style="background:#0A0A0A;border:1px solid #222"> 24 <div class="d-flex gap-3 text-secondary" style="font-size:12px;line-height:2"> 25 <span style="color:#666;min-width:64px"> 26 12:04:32 27 </span> 28 <span> 29 Starting build... 30 </span> 31 </div> 32 <div class="d-flex gap-3 text-secondary" style="font-size:12px;line-height:2"> 33 <span style="color:#666;min-width:64px"> 34 12:04:45 35 </span> 36 <span> 37 Compiling modules 38 </span> 39 </div> 40 <div class="d-flex gap-3" style="font-size:12px;line-height:2"> 41 <span style="color:#666;min-width:64px"> 42 12:05:01 43 </span> 44 <span style="color:#00FF41"> 45 Build succeeded in 29s 46 </span> 47 </div> 48 </div> 49 </div> 50 <div class="modal-footer border-secondary"> 51 <button type="button" class="btn btn-outline-secondary" data-bs-dismiss="modal"> 52 Close 53 </button> 54 <button type="button" class="btn fw-semibold" style="--bs-btn-bg:#00FF41;--bs-btn-color:#0A0A0A;--bs-btn-border-color:#00FF41;--bs-btn-hover-bg:#00E63A"> 55 Deploy 56 </button> 57 </div> 58 </div> 59 </div> 60 </div> 61 </div>
preview
HTML Structure
A semantic modal follows a predictable structure: backdrop overlay, dialog container with role="dialog" , header with title and close button, content area, and footer with actions. Bind the title with aria-labelledby and return focus to the trigger on close.
modal-structure.html wrap HTML
Copy 1 <div class="modal-backdrop"><!-- background overlay --></div> 2 <div class="modal" role="dialog" aria-modal="true" 3 aria-labelledby="dialog-title"> 4 <div class="modal-header"> 5 <h3 id="dialog-title" class="modal-title"> 6 Confirm Action 7 </h3> 8 <button class="modal-close" aria-label="Close">✕</button> 9 </div> 10 <div class="modal-body"> 11 <p>Are you sure you want to proceed?</p> 12 </div> 13 <div class="modal-footer"> 14 <button class="btn">Cancel</button> 15 <button class="btn btn-primary">Confirm</button> 16 </div> 17 </div>
Accessibility
Modals can easily trap or disorient keyboard and screen-reader users. Apply these patterns to keep dialogs usable for everyone.
Use a real <button> for the trigger, not a div or link styled as a button. Add role="dialog" and aria-modal="true" so assistive tech identifies the boundary. Bind the title to the dialog with aria-labelledby , or use aria-label when no visible title exists. Trap focus inside the open modal — Tab should cycle through focusable modal elements only. Close on Escape key and backdrop click, but not when the user clicks inside the dialog. Return focus to the trigger element when the modal closes. Keep the modal title focusable or move focus to the first focusable control on open. Disable background page scrolling while a modal is open to prevent loss of context. Best Practices
Keep modals focused on a single task or message — avoid long scrolling content. Use a clearly labeled close control in the header and a primary action in the footer. Animate entrance with opacity and transform , keeping transitions brief (200-300ms). Avoid stacking multiple modals; use a queue or replace the current dialog instead. Test modals at 320px wide viewports to ensure content does not overflow. Reserve modals for decisions that block the current workflow; inline content is often better for non-blocking information. Motion & Micro-interactions
Modal animations should guide attention without stealing it. The most effective pattern pairs a fading backdrop with a dialog that scales up slightly and slides in from above. Add subtle press and lift states to the trigger and close controls so the interaction feels tactile. Keep durations between 200ms and 300ms, use an easing curve that decelerates, and coordinate both entering and leaving states so the modal does not vanish instantly.
modal-motion HTML CSS JS Tailwind Bootstrap Live
Copy 1 <div class="modal-demo"> 2 <button class="trigger-btn" data-open="modal-motion"> 3 <svg class="trigger-icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" width="16" height="16"> 4 <path d="M12 5v14M5 12h14"/> 5 </svg> 6 Open Modal 7 </button> 8 <div class="modal-wrapper" id="modal-motion"> 9 <div class="modal-backdrop" data-close> 10 </div> 11 <div class="modal motion-modal" role="dialog" aria-modal="true" aria-labelledby="motion-title"> 12 <div class="modal-header"> 13 <h3 id="motion-title" class="modal-title"> 14 Deploy Changes 15 </h3> 16 <button class="modal-close" data-close aria-label="Close"> 17 <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" width="14" height="14"> 18 <path d="M18 6L6 18M6 6l12 12"/> 19 </svg> 20 </button> 21 </div> 22 <p class="modal-desc"> 23 Ready to push the latest build to production. The deployment will take about 30 seconds. 24 </p> 25 <div class="modal-footer"> 26 <button class="btn btn-secondary" data-close> 27 Cancel 28 </button> 29 <button class="btn btn-primary glow"> 30 Deploy 31 </button> 32 </div> 33 </div> 34 </div> 35 </div>
Copy 1 .modal-demo { 2 position:relative; 3 min-height:320px; 4 display:flex; 5 align-items:center; 6 justify-content:center; 7 font-family:system-ui, 8 sans-serif; 9 background:#0A0A0A 10 } 11 .trigger-btn { 12 display:flex; 13 align-items:center; 14 gap:8px; 15 padding:12px 28px; 16 border-radius:8px; 17 font-size:14px; 18 font-weight:600; 19 background:#00FF41; 20 color:#0A0A0A; 21 border:none; 22 cursor:pointer; 23 transition:all .2s 24 } 25 .trigger-btn:hover { 26 transform:translateY(-3px); 27 box-shadow:0 0 24px rgba(0, 28 255, 29 65, 30 .35) 31 } 32 .trigger-btn:active { 33 transform:translateY(0) scale(.98) 34 } 35 .trigger-icon { 36 animation:pulse 2s infinite 37 } 38 @keyframes pulse { 39 0%, 40 100% { 41 opacity:1 42 } 43 50% { 44 opacity:.6 45 } 46 } 47 .modal-wrapper { 48 position:absolute; 49 inset:0; 50 display:none; 51 align-items:center; 52 justify-content:center; 53 padding:24px; 54 z-index:50 55 } 56 .modal-wrapper.open { 57 display:flex 58 } 59 .modal-backdrop { 60 position:absolute; 61 inset:0; 62 background:rgba(0, 63 0, 64 0, 65 .65); 66 backdrop-filter:blur(4px); 67 opacity:0; 68 animation:fadeIn .25s ease forwards 69 } 70 .modal { 71 position:relative; 72 background:#111; 73 border:1px solid #2A2A3E; 74 border-radius:12px; 75 padding:0; 76 max-width:400px; 77 width:100%; 78 box-shadow:0 24px 64px rgba(0, 79 0, 80 0, 81 .5); 82 opacity:0; 83 transform:scale(.92) translateY(-20px); 84 animation:modalEnter .3s cubic-bezier(.16, 85 1, 86 .3, 87 1) forwards 88 } 89 .modal-wrapper.leaving .modal-backdrop { 90 animation:fadeOut .2s ease forwards 91 } 92 .modal-wrapper.leaving .modal { 93 animation:modalLeave .2s ease forwards 94 } 95 @keyframes fadeIn { 96 to { 97 opacity:1 98 } 99 } 100 @keyframes fadeOut { 101 to { 102 opacity:0 103 } 104 } 105 @keyframes modalEnter { 106 to { 107 opacity:1; 108 transform:scale(1) translateY(0) 109 } 110 } 111 @keyframes modalLeave { 112 to { 113 opacity:0; 114 transform:scale(.96) translateY(8px) 115 } 116 } 117 .modal-header { 118 display:flex; 119 align-items:center; 120 justify-content:space-between; 121 padding:20px 24px 0 122 } 123 .modal-title { 124 font-size:16px; 125 font-weight:700; 126 color:#E0E0E0; 127 margin:0 128 } 129 .modal-close { 130 width:28px; 131 height:28px; 132 border-radius:6px; 133 border:none; 134 background:transparent; 135 color:#808080; 136 cursor:pointer; 137 display:flex; 138 align-items:center; 139 justify-content:center; 140 transition:all .2s 141 } 142 .modal-close:hover { 143 background:rgba(255, 144 255, 145 255, 146 .05); 147 color:#E0E0E0; 148 transform:rotate(90deg) 149 } 150 .modal-desc { 151 font-size:13px; 152 color:#808080; 153 margin:12px 24px 20px; 154 line-height:1.5 155 } 156 .modal-footer { 157 display:flex; 158 gap:8px; 159 justify-content:flex-end; 160 padding:16px 24px; 161 border-top:1px solid #222 162 } 163 .btn { 164 padding:10px 16px; 165 border-radius:6px; 166 font-size:12px; 167 font-weight:600; 168 font-family:inherit; 169 cursor:pointer; 170 border:none; 171 transition:all .2s 172 } 173 .btn-secondary { 174 background:transparent; 175 color:#A0A0A0; 176 border:1px solid #2A2A3E 177 } 178 .btn-secondary:hover { 179 background:rgba(255, 180 255, 181 255, 182 .05); 183 color:#E0E0E0; 184 border-color:#3A3A4E 185 } 186 .btn-primary { 187 background:#00FF41; 188 color:#0A0A0A; 189 position:relative; 190 overflow:hidden 191 } 192 .btn-primary:hover { 193 transform:translateY(-2px); 194 box-shadow:0 0 20px rgba(0, 195 255, 196 65, 197 .4) 198 } 199 .btn-primary::after { 200 content:''; 201 position:absolute; 202 inset:0; 203 background:linear-gradient(120deg, 204 transparent, 205 rgba(255, 206 255, 207 255, 208 .25), 209 transparent); 210 transform:translateX(-100%); 211 transition:none 212 } 213 .btn-primary:hover::after { 214 transform:translateX(100%); 215 transition:transform .5s 216 } 217 .glow { 218 animation:glowPulse 2s infinite 219 } 220 @keyframes glowPulse { 221 0%, 222 100% { 223 box-shadow:0 0 0 rgba(0, 224 255, 225 65, 226 0) 227 } 228 50% { 229 box-shadow:0 0 18px rgba(0, 230 255, 231 65, 232 .25) 233 } 234 } 235 @media (prefers-reduced-motion:reduce) { 236 .modal-backdrop, 237 .modal, 238 .trigger-icon, 239 .btn-primary::after, 240 .glow { 241 animation:none !important; 242 transition:none !important 243 } 244 .modal { 245 opacity:1; 246 transform:none 247 } 248 }
untitled.js wrap JavaScript
Copy 1 const mOpen=document.querySelector('[data-open="modal-motion"]');const mWrap=document.getElementById('modal-motion');const mClose=()=>{mWrap.classList.add('leaving');setTimeout(()=>{mWrap.classList.remove('open','leaving')},200)};mOpen.addEventListener('click',()=>{mWrap.classList.add('open')});mWrap.querySelectorAll('[data-close]').forEach(el=>el.addEventListener('click',mClose));document.addEventListener('keydown',e=>{if(e.key==='Escape'&&mWrap.classList.contains('open'))mClose()})
Copy 1 <div class="relative min-h-[320px] flex items-center justify-center bg-[#0A0A0A] font-sans"> 2 <button data-open="modal-motion" class="flex items-center gap-2 px-7 py-3 rounded-lg text-sm font-semibold bg-[#00FF41] text-[#0A0A0A] hover:-translate-y-0.5 hover:shadow-[0_0_24px_rgba(0,255,65,0.35)] active:translate-y-0 active:scale-[0.98] transition-all"> 3 <svg class="w-4 h-4 animate-[pulse_2s_infinite]" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"> 4 <path d="M12 5v14M5 12h14"/> 5 </svg> 6 Open Modal 7 </button> 8 <div id="modal-motion" class="hidden absolute inset-0 items-center justify-center p-6 z-50"> 9 <div data-close class="absolute inset-0 bg-black/65 backdrop-blur-sm opacity-0 animate-[fadeIn_0.25s_ease_forwards]"> 10 </div> 11 <div role="dialog" aria-modal="true" aria-labelledby="motion-title" class="relative bg-[#111] border border-[#2A2A3E] rounded-xl max-w-[400px] w-full shadow-[0_24px_64px_rgba(0,0,0,0.5)] opacity-0 scale-[0.92] -translate-y-5 animate-[modalEnter_0.3s_cubic-bezier(0.16,1,0.3,1)_forwards]"> 12 <div class="flex items-center justify-between px-6 pt-5"> 13 <h3 id="motion-title" class="text-base font-bold text-[#E0E0E0]"> 14 Deploy Changes 15 </h3> 16 <button data-close aria-label="Close" class="w-7 h-7 rounded-md border-0 bg-transparent text-[#808080] hover:bg-white/5 hover:text-[#E0E0E0] hover:rotate-90 flex items-center justify-center transition-all"> 17 <svg class="w-3.5 h-3.5" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"> 18 <path d="M18 6L6 18M6 6l12 12"/> 19 </svg> 20 </button> 21 </div> 22 <p class="text-[13px] text-[#808080] mx-6 mt-3 mb-5 leading-relaxed"> 23 Ready to push the latest build to production. The deployment will take about 30 seconds. 24 </p> 25 <div class="flex gap-2 justify-end px-6 py-4 border-t border-[#222]"> 26 <button data-close class="px-4 py-2 rounded-md text-xs font-semibold bg-transparent text-[#A0A0A0] border border-[#2A2A3E] hover:bg-white/5 hover:text-[#E0E0E0] hover:border-[#3A3A4E] transition-all"> 27 Cancel 28 </button> 29 <button class="relative overflow-hidden px-4 py-2 rounded-md text-xs font-semibold bg-[#00FF41] text-[#0A0A0A] hover:-translate-y-0.5 hover:shadow-[0_0_20px_rgba(0,255,65,0.4)] transition-all group"> 30 Deploy 31 <span class="absolute inset-0 bg-gradient-to-r from-transparent via-white/25 to-transparent -translate-x-full group-hover:translate-x-full transition-transform duration-500"> 32 </span> 33 </button> 34 </div> 35 </div> 36 </div> 37 <style> 38 @keyframes fadeIn{to{opacity:1}}@keyframes modalEnter{to{opacity:1;transform:scale(1) translateY(0)}}@media (prefers-reduced-motion:reduce){*{animation:none!important;transition:none!important}} 39 </style> 40 </div>
Copy 1 <div class="d-flex align-items-center justify-content-center p-4" style="min-height:320px;background:#0A0A0A"> 2 <button class="btn fw-semibold d-inline-flex align-items-center gap-2" data-bs-toggle="modal" data-bs-target="#modalMotion" style="--bs-btn-bg:#00FF41;--bs-btn-color:#0A0A0A;--bs-btn-border-color:#00FF41;--bs-btn-hover-bg:#00E63A;--bs-btn-hover-border-color:#00E63A"> 3 <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"> 4 <path d="M12 5v14M5 12h14"/> 5 </svg> 6 Open Modal 7 </button> 8 <div class="modal fade" id="modalMotion" tabindex="-1" aria-labelledby="motion-title" aria-hidden="true" data-bs-theme="dark"> 9 <div class="modal-dialog modal-dialog-centered"> 10 <div class="modal-content" style="background:#111;border:1px solid #2A2A3E"> 11 <div class="modal-header border-secondary"> 12 <h5 class="modal-title fs-6 fw-bold" style="color:#E0E0E0" id="motion-title"> 13 Deploy Changes 14 </h5> 15 <button type="button" class="btn-close btn-close-white" data-bs-dismiss="modal" aria-label="Close"> 16 </button> 17 </div> 18 <div class="modal-body"> 19 <p class="text-secondary"> 20 Ready to push the latest build to production. The deployment will take about 30 seconds. 21 </p> 22 </div> 23 <div class="modal-footer border-secondary"> 24 <button type="button" class="btn btn-outline-secondary" data-bs-dismiss="modal"> 25 Cancel 26 </button> 27 <button type="button" class="btn fw-semibold" style="--bs-btn-bg:#00FF41;--bs-btn-color:#0A0A0A;--bs-btn-border-color:#00FF41;--bs-btn-hover-bg:#00E63A"> 28 Deploy 29 </button> 30 </div> 31 </div> 32 </div> 33 </div> 34 </div>
preview
📝 note
Respect prefers-reduced-motion . Wrap entrance and exit keyframes in a media query so users who opt out of animation see an instant, stable dialog. In Tailwind, combine motion-safe: with the animation utility, or disable animations globally inside the reduced-motion query.