Add a new project
Give your project a name — you can rename it later.
<button class="open-btn">Open Modal</button> <div class="backdrop"> <div class="dialog"> <button class="close">✕</button> <h3>Add a new project</h3> <p>Give your project a name — you can rename it later.</p> <input type="text" placeholder="My awesome project"> <div class="row"> <button class="cancel">Cancel</button> <button class="primary">Create project</button> </div> </div> </div>
.backdrop { position: fixed; inset: 0; background: rgba(15,23,42,.6); display: none; align-items: center; justify-content: center; z-index: 100; } .backdrop.open { display: flex; animation: fadeIn .2s; } .dialog { width: 100%; max-width: 440px; background: #fff; border-radius: 16px; padding: 28px; animation: pop .25s cubic-bezier(.2,.8,.3,1); } @keyframes pop { from { transform: scale(.95); opacity: 0; } to { transform: scale(1); opacity: 1; } }
// Grab every element BEFORE wiring up events const backdrop = document.querySelector('.backdrop'); const openBtn = document.querySelector('.open-btn'); const closeBtn = document.querySelector('.close'); const cancel = document.querySelector('.cancel'); // Toggle the .open class to show/hide openBtn.onclick = () => backdrop.classList.add('open'); closeBtn.onclick = () => backdrop.classList.remove('open'); cancel.onclick = () => backdrop.classList.remove('open'); // Click outside the dialog to close backdrop.onclick = (e) => { if (e.target === backdrop) backdrop.classList.remove('open'); }; // Escape key closes document.addEventListener('keydown', (e) => { if (e.key === 'Escape') backdrop.classList.remove('open'); });
Delete this project?
This can't be undone. All associated files and comments will be removed forever.
<button class="open-btn">Delete project</button> <div class="confirm"> <div class="icon">⚠</div> <h3>Delete this project?</h3> <p>This can't be undone. All associated files and comments will be removed forever.</p> <div class="row"> <button class="cancel">Cancel</button> <button class="delete">Yes, delete</button> </div> </div>
/* Destructive actions use a red tinted icon + red button */ .icon { width: 56px; height: 56px; border-radius: 50%; background: rgba(239, 68, 68, .12); color: #ef4444; margin: 0 auto 14px; } .delete { background: #ef4444; color: #fff; }
<button class="open-btn">Open cart</button> <div class="backdrop"></div> <aside class="drawer"> <h3>Your Cart (3)</h3> <div class="item"> <i class="ph-fill ph-sneaker"></i> <div><strong>Cloudstep Runners</strong><span>Size 10 · $129</span></div> </div> <div class="item"> <i class="ph-fill ph-t-shirt"></i> <div><strong>Studio Tee</strong><span>Medium · $45</span></div> </div> <div class="item"> <i class="ph-fill ph-watch"></i> <div><strong>Field Watch</strong><span>Black · $89</span></div> </div> <button class="open-btn">Checkout — $263</button> </aside>
.drawer { position: fixed; top: 0; right: 0; bottom: 0; width: 320px; background: #fff; transform: translateX(100%); transition: transform .35s cubic-bezier(.2,.8,.3,1); z-index: 101; } /* Slide in when .open is added */ .drawer.open { transform: translateX(0); }
Toast messages anchor to a corner — use for passive feedback, not for requiring input.
<div class="toast-wrap"> <div class="toast success"> <i class="ph-fill ph-check-circle"></i> <div><strong>Saved successfully</strong><small>Your changes are now live</small></div> </div> <div class="toast info"> <i class="ph-fill ph-info"></i> <div><strong>New version available</strong><small>Refresh to see what's new</small></div> </div> <div class="toast error"> <i class="ph-fill ph-x-circle"></i> <div><strong>Upload failed</strong><small>File exceeds 10 MB limit</small></div> </div> </div>
.toast-wrap { position: fixed; top: 20px; right: 20px; display: flex; flex-direction: column; gap: 10px; z-index: 1000; } .toast { animation: slideIn .3s cubic-bezier(.2,.8,.3,1); min-width: 260px; } @keyframes slideIn { from { transform: translateX(110%); opacity: 0; } to { transform: translateX(0); opacity: 1; } }
What's a popover?
It's like a tooltip with more room — good for quick forms, help text, or additional actions that don't need a full modal.
<div class="trigger"> <button>Show popover</button> <div class="popover"> <h4>What's a popover?</h4> <p>It's like a tooltip with more room — good for quick forms, help text, or additional actions that don't need a full modal.</p> </div> </div>
.trigger { position: relative; } .popover { position: absolute; top: calc(100% + 10px); width: 280px; background: #fff; border-radius: 12px; padding: 18px; box-shadow: 0 10px 30px rgba(0,0,0,.12); display: none; } .popover.open { display: block; } /* Triangle pointer using a rotated square */ .popover::before { content: ""; position: absolute; top: -6px; left: 20px; width: 12px; height: 12px; background: #fff; transform: rotate(45deg); }
Enable the "Labs" toggle in Settings to try early releases.
Upgrade now to keep access to Pro features.
Your card was declined. Please update your billing info.
All 1,247 files saved to cloud storage.
<div class="alert info"> <i class="ph-fill ph-info"></i> <div> <strong>New: Beta features available</strong> <p>Enable the "Labs" toggle in Settings to try early releases.</p> </div> <button>✕</button> </div> <div class="alert warn"> <i class="ph-fill ph-warning"></i> <div> <strong>Your trial ends in 3 days</strong> <p>Upgrade now to keep access to Pro features.</p> </div> <button>✕</button> </div> <div class="alert error"> <i class="ph-fill ph-x-circle"></i> <div> <strong>Payment failed</strong> <p>Your card was declined. Please update your billing info.</p> </div> <button>✕</button> </div> <div class="alert success"> <i class="ph-fill ph-check-circle"></i> <div> <strong>Backup completed</strong> <p>All 1,247 files saved to cloud storage.</p> </div> <button>✕</button> </div>
.alert { padding: 14px 18px; border-radius: 10px; display: flex; gap: 12px; border-left: 4px solid; } .alert.info { background: #dbeafe; color: #1e40af; border-left-color: #3b82f6; } .alert.warn { background: #fef3c7; color: #854d0e; border-left-color: #f59e0b; } .alert.error { background: #fee2e2; color: #991b1b; border-left-color: #ef4444; } .alert.success { background: #dcfce7; color: #166534; border-left-color: #10b981; }
Join the waitlist
Be first to know when we launch — no spam, one email when we're ready.
<button class="open-btn">Open full-screen</button> <div class="backdrop"> <button class="close">✕</button> <div class="fs"> <h2>Join the waitlist</h2> <p>Be first to know when we launch — no spam, one email when we're ready.</p> <form> <input type="email" placeholder="your@email.com"> <button type="submit">Join</button> </form> </div> </div>
.backdrop { position: fixed; inset: 0; background: rgba(0,0,0,.9); color: #fff; display: flex; align-items: center; justify-content: center; z-index: 100; } .fs { max-width: 560px; padding: 40px; text-align: center; }
<div class="gallery"> <img src="thumb1.jpg"> <img src="thumb2.jpg"> <img src="thumb3.jpg"> </div> <div class="backdrop"> <img class="big"> </div>
.gallery { display: grid; grid-template-columns: repeat(3, 1fr); gap: 10px; } .gallery img { aspect-ratio: 1; object-fit: cover; cursor: pointer; border-radius: 10px; } .big img { max-width: 90%; max-height: 80vh; }
document.querySelectorAll('.gallery img').forEach(thumb => { thumb.addEventListener('click', () => { // swap to a larger version of the same image document.querySelector('.big img').src = thumb.src.replace('w=300', 'w=1200'); document.querySelector('.backdrop').classList.add('open'); }); });