दिन 16: UI Components: Buttons, Cards, Navbar, Modal
✅ आज आप सीखेंगे
- Variants और sizes वाले components में सोचना
- Buttons, badges, avatars, alerts
- Cards, breadcrumbs और pagination
- सिर्फ़-CSS tabs और styled accordion
- Backdrop वाला dialog modal और toast notification
🏢 असली दुनिया में
असली company में आप शायद ही एक page style करते हैं – आप component library बनाते हैं जिसे हर page दोबारा इस्तेमाल करता है: एक button style, एक card, एक alert। Designer button radius बदले तो हर जगह बदलता है। आज का दिन आपको mini design system देता है जिसे आप हर client project में copy कर सकते हैं, school ERP या billing app screens समेत।
Buttons: एक base, कई variants
<style>
:root { --brand: #264de4; --brand-600: #1e40af; --ok: #15803d; --warn: #b45309; --err: #b91c1c; --ink: #0f172a; --muted: #64748b; --line: #e2e8f0; --r: 10px; }
* { box-sizing: border-box; }
.btn { display: inline-flex; align-items: center; gap: .4em; font: 600 .95rem system-ui; padding: .6em 1.1em; border-radius: var(--r); border: 1.5px solid transparent; cursor: pointer; text-decoration: none; transition: background-color .2s, transform .1s; margin: 4px; }
.btn:active { transform: translateY(1px); }
.btn:focus-visible { outline: 3px solid #f59e0b; outline-offset: 2px; }
.btn--primary { background: var(--brand); color: #fff; }
.btn--primary:hover { background: var(--brand-600); }
.btn--outline { border-color: var(--brand); color: var(--brand); background: #fff; }
.btn--ghost { color: var(--brand); background: transparent; }
.btn--danger { background: var(--err); color: #fff; }
.btn--sm { font-size: .8rem; }
.btn--lg { font-size: 1.1rem; padding: .75em 1.4em; }
.btn[disabled] { opacity: .5; pointer-events: none; }
</style>
<button class="btn btn--primary">Primary</button>
<button class="btn btn--outline">Outline</button>
<button class="btn btn--ghost">Ghost</button>
<button class="btn btn--danger">🗑 Delete</button><br>
<button class="btn btn--primary btn--sm">Small</button>
<button class="btn btn--primary btn--lg">Large</button>
<button class="btn btn--primary" disabled>Disabled</button>Badges, avatars और alerts
<style>
:root { --brand: #264de4; --brand-600: #1e40af; --ok: #15803d; --warn: #b45309; --err: #b91c1c; --ink: #0f172a; --muted: #64748b; --line: #e2e8f0; --r: 10px; }
* { box-sizing: border-box; }
.badge { display: inline-block; padding: 2px 10px; border-radius: 99px; font: 700 .72rem system-ui; letter-spacing: .02em; margin: 2px; }
.badge--ok { background: #dcfce7; color: #166534; } .badge--warn { background: #fef3c7; color: #92400e; } .badge--err { background: #fee2e2; color: #991b1b; }
.avatars { display: flex; margin: 12px 0; }
.avatar { width: 40px; height: 40px; border-radius: 50%; display: grid; place-items: center; color: #fff; font: 700 14px system-ui; border: 3px solid #fff; margin-left: -10px; }
.avatar:first-child { margin-left: 0; }
.alert { display: flex; gap: 10px; padding: 12px 14px; border-radius: var(--r); border: 1px solid; margin: 8px 0; }
.alert--info { background: #eff6ff; border-color: #bfdbfe; color: #1e3a8a; }
.alert--err { background: #fef2f2; border-color: #fecaca; color: #7f1d1d; }
</style>
<span class="badge badge--ok">Paid</span><span class="badge badge--warn">Pending</span><span class="badge badge--err">Overdue</span>
<div class="avatars"><span class="avatar" style="background:#264de4">AG</span><span class="avatar" style="background:#0891b2">RM</span><span class="avatar" style="background:#c2410c">SK</span><span class="avatar" style="background:#64748b">+5</span></div>
<div class="alert alert--info" role="status">ℹ️ <div><b>Fee reminder</b><br>Term 2 fee is due on 10 November.</div></div>
<div class="alert alert--err" role="alert">⚠️ <div><b>Payment failed</b><br>Your UPI request expired. Try again.</div></div>Breadcrumbs और pagination
<style>
:root { --brand: #264de4; --brand-600: #1e40af; --ok: #15803d; --warn: #b45309; --err: #b91c1c; --ink: #0f172a; --muted: #64748b; --line: #e2e8f0; --r: 10px; }
* { box-sizing: border-box; }
.crumbs ol { list-style: none; display: flex; flex-wrap: wrap; gap: 6px; padding: 0; margin: 0 0 14px; font-size: .9rem; }
.crumbs li + li::before { content: "›"; margin-right: 6px; color: var(--muted); }
.crumbs a { color: var(--brand); text-decoration: none; }
.crumbs [aria-current] { color: var(--muted); }
.pages { display: flex; gap: 6px; list-style: none; padding: 0; }
.pages a { display: grid; place-items: center; min-width: 38px; height: 38px; border: 1px solid var(--line); border-radius: 8px; text-decoration: none; color: var(--ink); }
.pages a:hover { border-color: var(--brand); }
.pages a[aria-current="page"] { background: var(--brand); color: #fff; border-color: var(--brand); }
</style>
<nav class="crumbs" aria-label="Breadcrumb"><ol><li><a href="#">Home</a></li><li><a href="#">Students</a></li><li><span aria-current="page">Class 10-A</span></li></ol></nav>
<nav aria-label="Pagination"><ul class="pages"><li><a href="#" aria-label="Previous">‹</a></li><li><a href="#">1</a></li><li><a href="#" aria-current="page">2</a></li><li><a href="#">3</a></li><li><a href="#" aria-label="Next">›</a></li></ul></nav>सिर्फ़-CSS tabs (radio hack) और accordion
<style>
:root { --brand: #264de4; --brand-600: #1e40af; --ok: #15803d; --warn: #b45309; --err: #b91c1c; --ink: #0f172a; --muted: #64748b; --line: #e2e8f0; --r: 10px; }
* { box-sizing: border-box; }
.tabs { display: flex; flex-wrap: wrap; border-bottom: 2px solid var(--line); }
.tabs input { position: absolute; opacity: 0; }
.tabs label { padding: 10px 16px; cursor: pointer; color: var(--muted); font-weight: 600; border-bottom: 3px solid transparent; margin-bottom: -2px; }
.tabs .panel { order: 99; width: 100%; padding: 14px 4px; display: none; }
.tabs input:checked + label { color: var(--brand); border-color: var(--brand); }
.tabs input:checked + label + .panel { display: block; }
.tabs input:focus-visible + label { outline: 3px solid #f59e0b; }
details.acc { border: 1px solid var(--line); border-radius: var(--r); margin: 8px 0; overflow: hidden; }
details.acc summary { padding: 12px 14px; cursor: pointer; font-weight: 600; list-style: none; display: flex; justify-content: space-between; }
details.acc summary::after { content: "+"; transition: transform .2s; }
details.acc[open] summary::after { transform: rotate(45deg); }
details.acc p { margin: 0; padding: 0 14px 12px; color: var(--muted); }
</style>
<div class="tabs">
<input type="radio" name="t" id="t1" checked><label for="t1">Description</label><div class="panel">Cashew fudge made with A-grade kaju and pure ghee.</div>
<input type="radio" name="t" id="t2"><label for="t2">Ingredients</label><div class="panel">Cashew 60%, sugar 38%, ghee 2%, silver vark.</div>
<input type="radio" name="t" id="t3"><label for="t3">Reviews (128)</label><div class="panel">★★★★★ “Best kaju katli in Jaipur.”</div>
</div>
<details class="acc"><summary>Shelf life</summary><p>Up to 15 days at room temperature.</p></details>
<details class="acc"><summary>Delivery areas</summary><p>All of Jaipur within 2 hours.</p></details>Radio trick साधारण product pages के लिए perfect है। पूरे ARIA tab semantics (arrow-key navigation, role="tablist") के लिए आप JS course में छोटा script लिखेंगे – CSS वही रहेगी।
Modal dialog और toast
<style>
:root { --brand: #264de4; --brand-600: #1e40af; --ok: #15803d; --warn: #b45309; --err: #b91c1c; --ink: #0f172a; --muted: #64748b; --line: #e2e8f0; --r: 10px; }
* { box-sizing: border-box; }
dialog.modal { border: 0; border-radius: 16px; padding: 0; width: min(92vw, 380px); box-shadow: 0 30px 60px rgb(0 0 0 / 30%); }
dialog.modal::backdrop { background: rgb(15 23 42 / 55%); backdrop-filter: blur(2px); }
dialog.modal[open] { animation: pop .2s ease-out; }
@keyframes pop { from { transform: scale(.95); opacity: 0; } }
.modal header { padding: 16px 18px; border-bottom: 1px solid var(--line); font-weight: 700; }
.modal .body { padding: 16px 18px; color: var(--muted); }
.modal footer { padding: 12px 18px; display: flex; justify-content: flex-end; gap: 8px; background: #f8fafc; }
.toast { position: fixed; left: 50%; bottom: 20px; transform: translate(-50%, 150%); background: var(--ink); color: #fff; padding: 12px 18px; border-radius: 12px; transition: transform .3s ease; }
.toast.show { transform: translate(-50%, 0); }
.btn { font: 600 .9rem system-ui; padding: .55em 1em; border-radius: 8px; border: 1px solid var(--line); background: #fff; cursor: pointer; }
.btn.primary { background: var(--err); color: #fff; border-color: var(--err); }
</style>
<button class="btn" onclick="dlg.showModal()">Delete order #1044</button>
<dialog class="modal" id="dlg" aria-labelledby="dh">
<header id="dh">Delete this order?</header>
<div class="body">Order #1044 (₹720) will be removed. This cannot be undone.</div>
<footer><form method="dialog"><button class="btn">Cancel</button> <button class="btn primary" onclick="setTimeout(function(){toast.classList.add('show'); setTimeout(function(){toast.classList.remove('show')}, 2200)}, 50)">Delete</button></form></footer>
</dialog>
<div class="toast" id="toast" role="status">✔ Order #1044 deleted</div>🏅 आज के Job Skills
Practice tasks
🏋️ Practice – ख़ुद करें
Solution देखें
Quick quiz
🧠 Quick Quiz – ख़ुद को जाँचें
Interview corner
💼 Interview Corner
Plain CSS में reusable component library कैसे बनाएँ?
Design tokens custom properties में, हर component की base class और variants/sizes के लिए modifier classes (BEM), flat selectors (single class), उपयोग का documentation, और components के अंदर page-specific overrides से बचना।
Native <dialog> बनाम div modal?
showModal() वाला dialog top layer, focus trap, Esc से बंद, inactive background और ::backdrop ख़ुद संभालता है – custom div modal से कम bugs और बेहतर accessibility।
सारांश
- Components = base class + modifiers, tokens से चलते।
- Badges, avatars, alerts, breadcrumbs, pagination छोटे patterns जो हर जगह दोबारा।
- radio + :checked से tabs; details से accordion।
- Modals के लिए dialog + ::backdrop; toasts के लिए transform।
Day 17: CSS architecture – BEM naming, file structure, reset, DevTools debugging और performance।
