UNPKG

gentelella

Version:

Gentelella v4 — free admin template. 60 pages, 20 chart variants, fully interactive inbox & kanban, live theme generator, component playground, PWA-ready. Vite 8, vanilla JS, no Bootstrap, no jQuery.

595 lines (564 loc) 28.2 kB
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Forms | Gentelella 2026 v4</title> <link rel="icon" href="../images/favicon.svg" type="image/svg+xml"> <link rel="preconnect" href="https://fonts.googleapis.com"> <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin> <link href="https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700&display=swap" rel="stylesheet"> <script type="module" src="/src/main-v4.js"></script> </head> <body data-shell="admin" data-page="forms" data-breadcrumb="Home > Forms > General"> <main class="main"> <div class="page-wrapper"> <div class="page-header"> <div class="page-header-row"> <div> <div class="page-pretitle">UI</div> <h1 class="page-title">Forms</h1> </div> <div class="page-actions"> <a class="btn btn-outline" href="form_advanced.html">Advanced</a> <a class="btn btn-outline" href="form_validation.html">Validation</a> <a class="btn btn-outline" href="form_wizards.html">Wizard</a> <a class="btn btn-outline" href="form_upload.html">Upload</a> </div> </div> </div> <!-- ── Section 1: Project form (full-width with side help) ── --> <div class="row col-8-4"> <div class="card"> <div class="card-header"> <div> <div class="card-title">New project</div> <div class="card-subtitle">Tell us about the project you're starting.</div> </div> </div> <div class="card-body"> <form> <div class="form-group"> <label class="form-label" for="projectName">Project name <span class="required">*</span></label> <input type="text" id="projectName" class="form-control" placeholder="e.g. Acme website redesign"> <div class="form-help">A short, recognizable name. You can change it later.</div> </div> <div class="form-row"> <div class="form-group"> <label class="form-label" for="client">Client</label> <select id="client" class="form-control"> <option>Acme Corp</option> <option>Globex Inc</option> <option>Initech</option> <option>Umbrella Co</option> </select> </div> <div class="form-group"> <label class="form-label" for="budget">Budget (USD)</label> <div class="input-affix"> <span class="affix prefix">$</span> <input type="number" id="budget" class="form-control" placeholder="25000"> <span class="affix">USD</span> </div> </div> </div> <div class="form-row"> <div class="form-group"> <label class="form-label" for="startDate">Start date</label> <input type="date" id="startDate" class="form-control"> </div> <div class="form-group"> <label class="form-label" for="endDate">End date</label> <input type="date" id="endDate" class="form-control"> </div> </div> <div class="form-group"> <label class="form-label" for="description">Description</label> <textarea id="description" class="form-control" placeholder="What problem are we solving?"></textarea> <div class="form-help">Markdown is supported.</div> </div> <div class="form-group"> <label class="form-label">Visibility</label> <div class="segmented" role="radiogroup"> <label><input type="radio" name="vis" checked><span>Private</span></label> <label><input type="radio" name="vis"><span>Team</span></label> <label><input type="radio" name="vis"><span>Public</span></label> </div> <div class="form-help">Private — only invited members. Public — anyone with the link.</div> </div> <div class="form-group"> <label class="form-label" for="tagInput">Tags</label> <div class="tag-input" id="tagInput" tabindex="0"> <span class="tag-pill">Web<button type="button" aria-label="Remove">×</button></span> <span class="tag-pill">Design<button type="button" aria-label="Remove">×</button></span> <span class="tag-pill">Q2<button type="button" aria-label="Remove">×</button></span> <input type="text" placeholder="Add tag…" aria-label="Add tag"> </div> <div class="form-help">Press Enter to add a tag.</div> </div> <div class="form-actions right"> <button type="reset" class="btn btn-outline">Save as draft</button> <button type="submit" class="btn btn-primary">Create project</button> </div> </form> </div> </div> <div style="display:flex;flex-direction:column;gap:16px"> <div class="card"> <div class="card-header"><div class="card-title">Tips</div></div> <div class="card-body"> <ul style="list-style:none;padding:0;margin:0;display:flex;flex-direction:column;gap:10px;font-size:12.5px;color:var(--text-secondary);line-height:1.5"> <li><strong style="color:var(--text)">Be specific</strong> with your project name — it shows up in URLs and notifications.</li> <li><strong style="color:var(--text)">Set a realistic budget</strong>. You can adjust it as scope changes.</li> <li><strong style="color:var(--text)">Tags</strong> help filter and group projects across your workspace.</li> </ul> </div> </div> <div class="card"> <div class="card-header"><div class="card-title">Need help?</div></div> <div class="card-body" style="font-size:12.5px;color:var(--text-secondary);line-height:1.5"> Read our <a href="faq.html">project guide</a> or reach out to <a href="#">support</a> — we usually reply within an hour. </div> </div> </div> </div> <!-- ── Section 2: Profile + avatar ── --> <div class="row col-2"> <div class="card"> <div class="card-header"> <div> <div class="card-title">Profile</div> <div class="card-subtitle">Avatar upload, names, bio.</div> </div> </div> <div class="card-body"> <div style="display:flex;gap:20px;align-items:center;margin-bottom:18px"> <label class="avatar-upload" for="avatar"> A <span class="overlay"> <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5"><path d="M3 7a2 2 0 012-2h2l2-2h6l2 2h2a2 2 0 012 2v10a2 2 0 01-2 2H5a2 2 0 01-2-2V7z"/><circle cx="12" cy="12" r="3.5"/></svg> </span> <input type="file" id="avatar" accept="image/*" hidden> </label> <div> <div style="font-size:14px;font-weight:600;color:var(--text);margin-bottom:4px">Aigars Silkalns</div> <div style="font-size:12.5px;color:var(--text-muted);margin-bottom:8px">Owner · aigars@example.com</div> <button class="btn btn-outline btn-sm">Upload new photo</button> </div> </div> <div class="form-row"> <div class="form-group"> <label class="form-label" for="firstName">First name</label> <input type="text" id="firstName" class="form-control" value="Aigars"> </div> <div class="form-group"> <label class="form-label" for="lastName">Last name</label> <input type="text" id="lastName" class="form-control" value="Silkalns"> </div> </div> <div class="form-group"> <label class="form-label" for="username">Username</label> <div class="input-affix"> <span class="affix prefix">colorlib.com/</span> <input type="text" id="username" class="form-control" value="aigars"> </div> </div> <div class="form-group"> <label class="form-label" for="bio">Bio</label> <textarea id="bio" class="form-control" placeholder="A few words about yourself…">Founder of Colorlib. Building Gentelella v4.</textarea> </div> </div> </div> <!-- Account security --> <div class="card"> <div class="card-header"> <div> <div class="card-title">Account security</div> <div class="card-subtitle">Password, 2FA, password strength.</div> </div> </div> <div class="card-body"> <div class="form-group"> <label class="form-label" for="currentPwd">Current password</label> <div class="input-group"> <svg class="input-icon" viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.5"><rect x="3" y="7" width="10" height="7" rx="1.5"/><path d="M5 7V5a3 3 0 016 0v2"/></svg> <input type="password" id="currentPwd" class="form-control" value="••••••••"> </div> </div> <div class="form-group"> <label class="form-label" for="newPwd">New password</label> <div class="input-group"> <svg class="input-icon" viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.5"><rect x="3" y="7" width="10" height="7" rx="1.5"/><path d="M5 7V5a3 3 0 016 0v2"/></svg> <input type="password" id="newPwd" class="form-control" placeholder="At least 12 characters" value="Goat-Stapler99!"> </div> <div class="password-strength s4"><div class="seg"></div><div class="seg"></div><div class="seg"></div><div class="seg"></div></div> <div class="password-strength-label">Strength: <strong>Strong</strong> · 12+ chars, mixed case, number, symbol</div> </div> <div class="form-group"> <label class="form-label">Two-factor authentication</label> <label class="switch"> <input type="checkbox" checked> <span class="track"></span> <span class="switch-label">Enabled — codes from authenticator app</span> </label> </div> <div class="form-group"> <label class="form-label">Verify with one-time code</label> <div class="otp-grid"> <input class="otp-input" aria-label="Digit 1 of 6" type="text" inputmode="numeric" pattern="[0-9]" maxlength="1" placeholder="·"> <input class="otp-input" aria-label="Digit 2 of 6" type="text" inputmode="numeric" pattern="[0-9]" maxlength="1" placeholder="·"> <input class="otp-input" aria-label="Digit 3 of 6" type="text" inputmode="numeric" pattern="[0-9]" maxlength="1" placeholder="·"> <input class="otp-input" aria-label="Digit 4 of 6" type="text" inputmode="numeric" pattern="[0-9]" maxlength="1" placeholder="·"> <input class="otp-input" aria-label="Digit 5 of 6" type="text" inputmode="numeric" pattern="[0-9]" maxlength="1" placeholder="·"> <input class="otp-input" aria-label="Digit 6 of 6" type="text" inputmode="numeric" pattern="[0-9]" maxlength="1" placeholder="·"> </div> </div> </div> </div> </div> <!-- ── Section 3: Preferences (sliders, switches, color, segmented) ── --> <div class="row col-2"> <div class="card"> <div class="card-header"> <div> <div class="card-title">Preferences</div> <div class="card-subtitle">Range sliders, switches, segmented controls.</div> </div> </div> <div class="card-body"> <div class="form-group"> <label class="form-label" for="volume">Notification volume</label> <div class="slider-row"> <input type="range" id="volume" class="slider" min="0" max="100" value="62"> <span class="slider-value" data-slider-display="volume">62%</span> </div> </div> <div class="form-group"> <label class="form-label" for="font-size">Font size</label> <div class="slider-row"> <input type="range" id="font-size" class="slider" min="12" max="20" step="1" value="14"> <span class="slider-value" data-slider-display="font-size">14px</span> </div> </div> <div class="form-group"> <label class="form-label">Theme</label> <div class="segmented" role="radiogroup"> <label><input type="radio" name="pref-theme"><span>Light</span></label> <label><input type="radio" name="pref-theme"><span>Dark</span></label> <label><input type="radio" name="pref-theme" checked><span>System</span></label> </div> </div> <div class="form-group"> <label class="form-label">Density</label> <div class="segmented" role="radiogroup"> <label><input type="radio" name="pref-density" checked><span>Cozy</span></label> <label><input type="radio" name="pref-density"><span>Comfortable</span></label> <label><input type="radio" name="pref-density"><span>Compact</span></label> </div> </div> <div class="form-group" style="display:flex;flex-direction:column;gap:8px"> <label class="switch"><input type="checkbox" checked><span class="track"></span><span class="switch-label">Send weekly summary email</span></label> <label class="switch"><input type="checkbox"><span class="track"></span><span class="switch-label">Beta features</span></label> <label class="switch"><input type="checkbox" checked><span class="track"></span><span class="switch-label">Sounds for incoming messages</span></label> </div> </div> </div> <!-- Color + rating + stepper --> <div class="card"> <div class="card-header"> <div> <div class="card-title">Project meta</div> <div class="card-subtitle">Color tag, priority, team size, rating.</div> </div> </div> <div class="card-body"> <div class="form-group"> <label class="form-label">Project color</label> <div class="color-grid" role="radiogroup"> <span class="color-swatch active" style="background:var(--primary)" data-color="primary"></span> <span class="color-swatch" style="background:var(--azure)" data-color="azure"></span> <span class="color-swatch" style="background:var(--blue)" data-color="blue"></span> <span class="color-swatch" style="background:var(--purple)" data-color="purple"></span> <span class="color-swatch" style="background:var(--pink)" data-color="pink"></span> <span class="color-swatch" style="background:var(--red)" data-color="red"></span> <span class="color-swatch" style="background:var(--orange)" data-color="orange"></span> <span class="color-swatch" style="background:var(--yellow)" data-color="yellow"></span> <span class="color-swatch" style="background:var(--green)" data-color="green"></span> <span class="color-swatch" style="background:var(--cyan)" data-color="cyan"></span> </div> </div> <div class="form-group"> <label class="form-label" for="priority">Priority</label> <select id="priority" class="form-control"> <option>Low</option> <option selected>Medium</option> <option>High</option> <option>Critical</option> </select> </div> <div class="form-group"> <label class="form-label">Team size</label> <div class="stepper"> <button type="button" data-step="-1"></button> <input type="number" value="6" min="1" max="50" aria-label="Team size"> <button type="button" data-step="1">+</button> </div> </div> <div class="form-group"> <label class="form-label">Project rating</label> <div class="rating" data-rating="4"> <button type="button" class="on" aria-label="1 star"><svg viewBox="0 0 16 16"><path d="M8 1l2 5 5 .5-4 3.5 1 5-4-2.5-4 2.5 1-5-4-3.5 5-.5z"/></svg></button> <button type="button" class="on" aria-label="2 stars"><svg viewBox="0 0 16 16"><path d="M8 1l2 5 5 .5-4 3.5 1 5-4-2.5-4 2.5 1-5-4-3.5 5-.5z"/></svg></button> <button type="button" class="on" aria-label="3 stars"><svg viewBox="0 0 16 16"><path d="M8 1l2 5 5 .5-4 3.5 1 5-4-2.5-4 2.5 1-5-4-3.5 5-.5z"/></svg></button> <button type="button" class="on" aria-label="4 stars"><svg viewBox="0 0 16 16"><path d="M8 1l2 5 5 .5-4 3.5 1 5-4-2.5-4 2.5 1-5-4-3.5 5-.5z"/></svg></button> <button type="button" aria-label="5 stars"><svg viewBox="0 0 16 16"><path d="M8 1l2 5 5 .5-4 3.5 1 5-4-2.5-4 2.5 1-5-4-3.5 5-.5z"/></svg></button> </div> </div> <div class="form-group"> <label class="form-label">Cover image</label> <label class="file-input" for="cover"> <span class="file-input-trigger">Choose file</span> <span class="file-input-name" id="cover-name">cover-redesign-final.jpg</span> <input id="cover" type="file" accept="image/*"> </label> </div> </div> </div> </div> <!-- ── Section 4: Search with suggestions, validation states ── --> <div class="row col-2"> <div class="card"> <div class="card-header"> <div> <div class="card-title">Search with suggestions</div> <div class="card-subtitle">Live autocomplete pattern.</div> </div> </div> <div class="card-body"> <div class="form-group"> <label class="form-label" for="searchInput">Search clients</label> <div class="input-group"> <svg class="input-icon" viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.5"><circle cx="7" cy="7" r="5"/><path d="M11 11l3.5 3.5"/></svg> <input type="text" id="searchInput" class="form-control" value="acm"> </div> <div class="search-suggest"> <div class="search-suggest-row"><svg width="14" height="14" viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.5"><circle cx="8" cy="8" r="6"/></svg><span><mark>Acm</mark>e Corp</span><span class="meta">Pro · NYC</span></div> <div class="search-suggest-row"><svg width="14" height="14" viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.5"><circle cx="8" cy="8" r="6"/></svg><span><mark>Acm</mark>e Industries</span><span class="meta">Business · Berlin</span></div> <div class="search-suggest-row"><svg width="14" height="14" viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.5"><circle cx="8" cy="8" r="6"/></svg><span><mark>Acm</mark>e Studio</span><span class="meta">Starter · Tokyo</span></div> </div> </div> </div> </div> <div class="card"> <div class="card-header"> <div> <div class="card-title">Validation states</div> <div class="card-subtitle">Helper, error, disabled, and required.</div> </div> </div> <div class="card-body"> <div class="form-group"> <label class="form-label" for="email-ok">Email <span class="required">*</span></label> <input type="email" id="email-ok" class="form-control" value="aigars@example.com"> <div class="form-help">We'll never share your email.</div> </div> <div class="form-group"> <label class="form-label" for="email-bad">Backup email</label> <input type="email" id="email-bad" class="form-control is-invalid" value="not-an-email"> <div class="form-error">Please enter a valid email address.</div> </div> <div class="form-group"> <label class="form-label" for="readonly-input">Account ID (read-only)</label> <input type="text" id="readonly-input" class="form-control" value="acct_8f3k29df3lkj" disabled> <div class="form-help">Generated automatically. Cannot be changed.</div> </div> <div class="form-group"> <label class="form-label" for="char-count">Tagline (max 80)</label> <textarea id="char-count" class="form-control" maxlength="80" data-char-counter>The free Bootstrap admin template, redesigned for 2026.</textarea> <div class="form-help"><span data-char-display="char-count">56</span>/80 characters</div> </div> </div> </div> </div> <!-- ── Section 5: Advanced controls (date-range, multi-select, rich text) ── --> <div class="row col-2"> <div class="card"> <div class="card-header"> <div> <div class="card-title">Date range</div> <div class="card-subtitle">Two-month picker · presets · keyboard nav</div> </div> </div> <div class="card-body"> <div class="form-group"> <label class="form-label" for="dr-input">Report period</label> <div class="date-range" data-date-range> <input id="dr-input" class="form-control" placeholder="Pick a date range" aria-label="Date range"> </div> <div class="form-help">Click the input to open the picker. Built from scratch — no library.</div> </div> </div> </div> <div class="card"> <div class="card-header"> <div> <div class="card-title">Multi-select with chips</div> <div class="card-subtitle">Type to filter · Enter to add · Backspace to remove</div> </div> </div> <div class="card-body"> <div class="form-group"> <label class="form-label">Project tags</label> <div class="multi-select" data-multi-select> <select multiple hidden> <option value="Design" selected>Design</option> <option value="Engineering" selected>Engineering</option> <option value="Product">Product</option> <option value="Marketing">Marketing</option> <option value="Support">Support</option> <option value="Sales">Sales</option> <option value="Operations">Operations</option> <option value="Legal">Legal</option> <option value="Finance">Finance</option> <option value="HR">HR</option> </select> </div> <div class="form-help">Bound to a real <code>&lt;select multiple&gt;</code> so it submits with any form.</div> </div> </div> </div> </div> <div class="row col-1"> <div class="card"> <div class="card-header"> <div> <div class="card-title">Rich text editor</div> <div class="card-subtitle">Bold · italic · headings · lists · links · code · keyboard shortcuts</div> </div> </div> <div class="card-body"> <div class="form-group" style="margin-bottom:0"> <label class="form-label" for="rt-bio">About</label> <div class="rich-text" data-rich-text> <textarea id="rt-bio" name="bio" hidden>&lt;p&gt;Click any button in the toolbar — &lt;strong&gt;bold&lt;/strong&gt;, &lt;em&gt;italic&lt;/em&gt;, lists, links, code blocks. Try &lt;kbd&gt;⌘B&lt;/kbd&gt; / &lt;kbd&gt;⌘I&lt;/kbd&gt; / &lt;kbd&gt;⌘K&lt;/kbd&gt;. The hidden &lt;code&gt;&amp;lt;textarea&amp;gt;&lt;/code&gt; stays in sync so a parent form picks it up on submit.&lt;/p&gt;</textarea> </div> </div> </div> </div> </div> </div> </main> <script type="module"> // Slider value display document.querySelectorAll('input[type="range"].slider').forEach((r) => { const display = document.querySelector(`[data-slider-display="${r.id}"]`); if (!display) return; const suffix = r.id === 'volume' ? '%' : (r.id === 'font-size' ? 'px' : ''); r.addEventListener('input', () => { display.textContent = r.value + suffix; }); }); // Color swatch selection document.querySelectorAll('.color-grid').forEach((grid) => { grid.addEventListener('click', (e) => { const sw = e.target.closest('.color-swatch'); if (!sw) return; grid.querySelectorAll('.color-swatch').forEach((s) => s.classList.remove('active')); sw.classList.add('active'); }); }); // Stepper +/- document.querySelectorAll('.stepper').forEach((step) => { const input = step.querySelector('input'); step.querySelectorAll('button[data-step]').forEach((btn) => { btn.addEventListener('click', () => { const delta = parseInt(btn.dataset.step, 10); const min = parseInt(input.min || '-Infinity', 10); const max = parseInt(input.max || 'Infinity', 10); const next = Math.max(min, Math.min(max, (parseInt(input.value, 10) || 0) + delta)); input.value = next; input.dispatchEvent(new Event('input', { bubbles: true })); }); }); }); // Tag input document.querySelectorAll('.tag-input').forEach((wrap) => { const input = wrap.querySelector('input'); wrap.addEventListener('click', (e) => { if (e.target === wrap) input.focus(); const close = e.target.closest('.tag-pill button'); if (close) close.closest('.tag-pill').remove(); }); input.addEventListener('keydown', (e) => { if (e.key === 'Enter' && input.value.trim()) { e.preventDefault(); const pill = document.createElement('span'); pill.className = 'tag-pill'; pill.innerHTML = input.value.trim().replace(/[<>&]/g, '') + '<button type="button" aria-label="Remove">×</button>'; wrap.insertBefore(pill, input); input.value = ''; } else if (e.key === 'Backspace' && !input.value) { const last = wrap.querySelector('.tag-pill:last-of-type'); if (last) last.remove(); } }); }); // Rating document.querySelectorAll('.rating').forEach((rating) => { const stars = [...rating.querySelectorAll('button')]; stars.forEach((star, i) => { star.addEventListener('click', () => { stars.forEach((s, j) => s.classList.toggle('on', j <= i)); rating.dataset.rating = String(i + 1); }); }); }); // File input — show selected name document.querySelectorAll('.file-input input[type="file"]').forEach((inp) => { const display = inp.closest('.file-input').querySelector('.file-input-name'); if (!display) return; inp.addEventListener('change', () => { if (inp.files?.[0]) display.textContent = inp.files[0].name; }); }); // OTP — auto-advance document.querySelectorAll('.otp-grid').forEach((grid) => { const inputs = [...grid.querySelectorAll('.otp-input')]; inputs.forEach((inp, i) => { inp.addEventListener('input', () => { if (inp.value && i < inputs.length - 1) inputs[i + 1].focus(); }); inp.addEventListener('keydown', (e) => { if (e.key === 'Backspace' && !inp.value && i > 0) inputs[i - 1].focus(); }); }); }); // Char counter document.querySelectorAll('[data-char-counter]').forEach((el) => { const display = document.querySelector(`[data-char-display="${el.id}"]`); if (!display) return; const update = () => { display.textContent = String(el.value.length); }; el.addEventListener('input', update); update(); }); // Password strength const newPwd = document.getElementById('newPwd'); if (newPwd) { const meter = newPwd.closest('.form-group')?.querySelector('.password-strength'); const label = newPwd.closest('.form-group')?.querySelector('.password-strength-label strong'); const score = (v) => { let s = 0; if (v.length >= 8) s++; if (v.length >= 12) s++; if (/[A-Z]/.test(v) && /[a-z]/.test(v)) s++; if (/\d/.test(v) && /[^A-Za-z0-9]/.test(v)) s++; return s; }; const labels = ['Empty', 'Weak', 'Fair', 'Good', 'Strong']; newPwd.addEventListener('input', () => { const s = score(newPwd.value); if (meter) meter.className = `password-strength s${s}`; if (label) label.textContent = labels[s]; }); } </script> </body> </html>