|$ curl https://forge-ai.dev/api/markdown?path=docs/components/forms
$cat docs/forms.md
updated Recently·15 min read·published
Forms
◆CSS◆HTML◆UI◆Intermediate
Form Components
Forms are the primary way users submit data. These examples demonstrate clean form layouts with proper labels, validation states, input groups, and error handling — styled with modern CSS and zero dependencies.
Input with Label
Every input must have an associated label for accessibility. Use the for attribute matching the input id to connect them.
form-inputs
Live
untitled.html
HTML
| 1 | <div class="form"> |
| 2 | <div class="field"> |
| 3 | <label class="label" for="name2"> |
| 4 | Full Name |
| 5 | </label> |
| 6 | <input class="input" id="name2" type="text" placeholder="Enter your name" /> |
| 7 | </div> |
| 8 | <div class="field"> |
| 9 | <label class="label" for="email2"> |
| 10 | Email Address |
| 11 | </label> |
| 12 | <input class="input" id="email2" type="email" placeholder="your@email.com" /> |
| 13 | <span class="error-msg" id="email-error"> |
| 14 | <svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"> |
| 15 | <circle cx="12" cy="12" r="10"/> |
| 16 | <line x1="15" y1="9" x2="9" y2="15"/> |
| 17 | <line x1="9" y1="9" x2="15" y2="15"/> |
| 18 | </svg> |
| 19 | Please enter a valid email |
| 20 | </span> |
| 21 | </div> |
| 22 | <div class="field"> |
| 23 | <label class="label" for="msg2"> |
| 24 | Message |
| 25 | <span id="msg-count" style="color:#525252;font-weight:400"> |
| 26 | (0) |
| 27 | </span> |
| 28 | </label> |
| 29 | <textarea class="input" id="msg2" rows="3" placeholder="Write your message..." maxlength="200"> |
| 30 | </textarea> |
| 31 | </div> |
| 32 | <button class="btn" style="width:100%" id="submit-btn"> |
| 33 | Submit |
| 34 | </button> |
| 35 | </div> |
untitled.css
CSS
| 1 | .form { |
| 2 | max-width:400px; |
| 3 | margin:32px auto; |
| 4 | font-family:system-ui, |
| 5 | sans-serif |
| 6 | } |
| 7 | .field { |
| 8 | margin-bottom:20px |
| 9 | } |
| 10 | .label { |
| 11 | display:block; |
| 12 | font-size:12px; |
| 13 | font-weight:600; |
| 14 | color:#A0A0A0; |
| 15 | margin-bottom:6px |
| 16 | } |
| 17 | .input { |
| 18 | width:100%; |
| 19 | padding:10px 14px; |
| 20 | border-radius:8px; |
| 21 | font-size:13px; |
| 22 | font-family:inherit; |
| 23 | background:#0A0A0A; |
| 24 | border:1.5px solid #2A2A3E; |
| 25 | color:#E0E0E0; |
| 26 | outline:none; |
| 27 | transition:border-color .2s, |
| 28 | box-shadow .2s; |
| 29 | box-sizing:border-box |
| 30 | } |
| 31 | .input:focus { |
| 32 | border-color:#00FF41; |
| 33 | box-shadow:0 0 0 3px rgba(0, |
| 34 | 255, |
| 35 | 65, |
| 36 | .1) |
| 37 | } |
| 38 | .input::placeholder { |
| 39 | color:#525252 |
| 40 | } |
| 41 | .input.input-error { |
| 42 | border-color:#EF4444 |
| 43 | } |
| 44 | .input.input-error:focus { |
| 45 | border-color:#EF4444; |
| 46 | box-shadow:0 0 0 3px rgba(239, |
| 47 | 68, |
| 48 | 68, |
| 49 | .1) |
| 50 | } |
| 51 | .input.valid { |
| 52 | border-color:#22C55E |
| 53 | } |
| 54 | .error-msg { |
| 55 | font-size:11px; |
| 56 | color:#EF4444; |
| 57 | margin-top:4px; |
| 58 | display:none; |
| 59 | align-items:center; |
| 60 | gap:4px |
| 61 | } |
| 62 | .error-msg.show { |
| 63 | display:flex |
| 64 | } |
| 65 | textarea.input { |
| 66 | resize:vertical; |
| 67 | font-family:inherit |
| 68 | } |
| 69 | .btn { |
| 70 | padding:10px 24px; |
| 71 | border-radius:8px; |
| 72 | font-size:13px; |
| 73 | font-weight:600; |
| 74 | font-family:inherit; |
| 75 | cursor:pointer; |
| 76 | background:#00FF41; |
| 77 | color:#0A0A0A; |
| 78 | border:none; |
| 79 | transition:all .2s |
| 80 | } |
| 81 | .btn:hover { |
| 82 | background:#00E63A |
| 83 | } |
| 84 | .btn:disabled { |
| 85 | opacity:.5; |
| 86 | cursor:not-allowed; |
| 87 | transform:none!important; |
| 88 | box-shadow:none!important |
| 89 | } |
untitled.js
JavaScript
| 1 | const email=document.getElementById('email2');const err=document.getElementById('email-error');email.addEventListener('blur',()=>{const v=email.value.trim();if(v&&!v.includes('@')){email.classList.add('input-error');err.classList.add('show')}else{email.classList.remove('input-error');err.classList.remove('show');if(v)email.classList.add('valid')}});email.addEventListener('input',()=>{email.classList.remove('input-error','valid');err.classList.remove('show')});const msg=document.getElementById('msg2');const count=document.getElementById('msg-count');msg.addEventListener('input',()=>{count.textContent='('+msg.value.length+')'}) |
Select & Checkbox
Styled select dropdowns and checkbox inputs using clean CSS. The select uses appearance: none with a custom SVG arrow for consistent cross-browser styling.
form-select
Live
untitled.html
HTML
| 1 | <div class="form"> |
| 2 | <div class="field"> |
| 3 | <label class="label" for="country"> |
| 4 | Country |
| 5 | </label> |
| 6 | <select class="select" id="country"> |
| 7 | <option> |
| 8 | United States |
| 9 | </option> |
| 10 | <option> |
| 11 | Canada |
| 12 | </option> |
| 13 | <option> |
| 14 | United Kingdom |
| 15 | </option> |
| 16 | <option> |
| 17 | Germany |
| 18 | </option> |
| 19 | <option> |
| 20 | Japan |
| 21 | </option> |
| 22 | </select> |
| 23 | </div> |
| 24 | <div class="field"> |
| 25 | <span class="label"> |
| 26 | Preferences |
| 27 | <span id="cb-count" style="color:#525252;font-weight:400"> |
| 28 | (1 selected) |
| 29 | </span> |
| 30 | </span> |
| 31 | <div class="checkbox-group"> |
| 32 | <label class="checkbox-label"> |
| 33 | <input type="checkbox" checked /> |
| 34 | Email notifications |
| 35 | </label> |
| 36 | <label class="checkbox-label"> |
| 37 | <input type="checkbox" /> |
| 38 | SMS updates |
| 39 | </label> |
| 40 | <label class="checkbox-label"> |
| 41 | <input type="checkbox" /> |
| 42 | Weekly digest |
| 43 | </label> |
| 44 | </div> |
| 45 | </div> |
| 46 | </div> |
untitled.css
CSS
| 1 | .form { |
| 2 | max-width:400px; |
| 3 | margin:32px auto; |
| 4 | font-family:system-ui, |
| 5 | sans-serif |
| 6 | } |
| 7 | .field { |
| 8 | margin-bottom:20px |
| 9 | } |
| 10 | .label { |
| 11 | display:block; |
| 12 | font-size:12px; |
| 13 | font-weight:600; |
| 14 | color:#A0A0A0; |
| 15 | margin-bottom:6px |
| 16 | } |
| 17 | .select { |
| 18 | width:100%; |
| 19 | padding:10px 14px; |
| 20 | padding-right:36px; |
| 21 | border-radius:8px; |
| 22 | font-size:13px; |
| 23 | font-family:inherit; |
| 24 | background:#0A0A0A; |
| 25 | border:1.5px solid #2A2A3E; |
| 26 | color:#E0E0E0; |
| 27 | outline:none; |
| 28 | appearance:none; |
| 29 | cursor:pointer; |
| 30 | transition:border-color .2s; |
| 31 | box-sizing:border-box; |
| 32 | background-image:url("data:image/svg+xml, |
| 33 | %3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 24 24' fill='none' stroke='%23525252' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='6 9 12 15 18 9'%3E%3C/polyline%3E%3C/svg%3E"); |
| 34 | background-repeat:no-repeat; |
| 35 | background-position:right 12px center |
| 36 | } |
| 37 | .select:focus { |
| 38 | border-color:#00FF41; |
| 39 | box-shadow:0 0 0 3px rgba(0, |
| 40 | 255, |
| 41 | 65, |
| 42 | .1) |
| 43 | } |
| 44 | .checkbox-group { |
| 45 | display:flex; |
| 46 | flex-direction:column; |
| 47 | gap:10px |
| 48 | } |
| 49 | .checkbox-label { |
| 50 | display:flex; |
| 51 | align-items:center; |
| 52 | gap:10px; |
| 53 | font-size:13px; |
| 54 | color:#A0A0A0; |
| 55 | cursor:pointer |
| 56 | } |
| 57 | .checkbox-label input[type="checkbox"] { |
| 58 | width:18px; |
| 59 | height:18px; |
| 60 | accent-color:#00FF41; |
| 61 | cursor:pointer; |
| 62 | border-radius:4px; |
| 63 | flex-shrink:0 |
| 64 | } |
untitled.js
JavaScript
| 1 | const cbs=document.querySelectorAll('.checkbox-label input[type=checkbox]');const ct=document.getElementById('cb-count');cbs.forEach(cb=>{cb.addEventListener('change',()=>{const n=document.querySelectorAll('.checkbox-label input[type=checkbox]:checked').length;ct.textContent='('+n+' selected)'})}) |
Form Layout
A complete sign-up form with grid layout, inline fields, and validation-ready styling. This is a production-ready form card you can drop into any project.
signup-form
Live
untitled.html
HTML
| 1 | <div class="form-card"> |
| 2 | <h2 class="form-title"> |
| 3 | Create Account |
| 4 | </h2> |
| 5 | <p class="form-sub"> |
| 6 | Get started with a free account |
| 7 | </p> |
| 8 | <div class="row"> |
| 9 | <div class="field"> |
| 10 | <label class="label"> |
| 11 | First Name |
| 12 | </label> |
| 13 | <input class="input" placeholder="John" /> |
| 14 | </div> |
| 15 | <div class="field"> |
| 16 | <label class="label"> |
| 17 | Last Name |
| 18 | </label> |
| 19 | <input class="input" placeholder="Doe" /> |
| 20 | </div> |
| 21 | </div> |
| 22 | <div class="field"> |
| 23 | <label class="label"> |
| 24 | |
| 25 | </label> |
| 26 | <input class="input" type="email" placeholder="john@example.com" /> |
| 27 | </div> |
| 28 | <div class="row"> |
| 29 | <div class="field"> |
| 30 | <label class="label"> |
| 31 | Password |
| 32 | </label> |
| 33 | <div class="pw-wrap"> |
| 34 | <input class="input" id="pw1" type="password" placeholder="••••••••" /> |
| 35 | <button class="pw-toggle" data-for="pw1" aria-label="Toggle password"> |
| 36 | <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" width="16" height="16"> |
| 37 | <path d="M1 12s4-8 11-8 11 8 11 8-4 8-11 8-11-8-11-8z"/> |
| 38 | <circle cx="12" cy="12" r="3"/> |
| 39 | </svg> |
| 40 | </button> |
| 41 | </div> |
| 42 | </div> |
| 43 | <div class="field"> |
| 44 | <label class="label"> |
| 45 | Confirm |
| 46 | </label> |
| 47 | <div class="pw-wrap"> |
| 48 | <input class="input" id="pw2" type="password" placeholder="••••••••" /> |
| 49 | <button class="pw-toggle" data-for="pw2" aria-label="Toggle password"> |
| 50 | <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" width="16" height="16"> |
| 51 | <path d="M1 12s4-8 11-8 11 8 11 8-4 8-11 8-11-8-11-8z"/> |
| 52 | <circle cx="12" cy="12" r="3"/> |
| 53 | </svg> |
| 54 | </button> |
| 55 | </div> |
| 56 | </div> |
| 57 | </div> |
| 58 | <button class="btn"> |
| 59 | Create Account |
| 60 | </button> |
| 61 | <hr class="divider" /> |
| 62 | <p class="terms"> |
| 63 | By signing up you agree to our |
| 64 | <a href="#"> |
| 65 | Terms of Service |
| 66 | </a> |
| 67 | </p> |
| 68 | </div> |
untitled.css
CSS
| 1 | .form-card { |
| 2 | max-width:480px; |
| 3 | margin:24px auto; |
| 4 | background:#111; |
| 5 | border:1px solid #222; |
| 6 | border-radius:12px; |
| 7 | padding:28px; |
| 8 | font-family:system-ui, |
| 9 | sans-serif |
| 10 | } |
| 11 | .form-title { |
| 12 | font-size:18px; |
| 13 | font-weight:700; |
| 14 | color:#E0E0E0; |
| 15 | margin:0 0 4px 0 |
| 16 | } |
| 17 | .form-sub { |
| 18 | font-size:12px; |
| 19 | color:#808080; |
| 20 | margin:0 0 24px 0 |
| 21 | } |
| 22 | .row { |
| 23 | display:grid; |
| 24 | grid-template-columns:1fr 1fr; |
| 25 | gap:12px; |
| 26 | margin-bottom:16px |
| 27 | } |
| 28 | .field { |
| 29 | margin-bottom:16px |
| 30 | } |
| 31 | .label { |
| 32 | display:block; |
| 33 | font-size:11px; |
| 34 | font-weight:600; |
| 35 | color:#A0A0A0; |
| 36 | margin-bottom:5px |
| 37 | } |
| 38 | .input { |
| 39 | width:100%; |
| 40 | padding:9px 12px; |
| 41 | border-radius:6px; |
| 42 | font-size:13px; |
| 43 | font-family:inherit; |
| 44 | background:#0A0A0A; |
| 45 | border:1.5px solid #2A2A3E; |
| 46 | color:#E0E0E0; |
| 47 | outline:none; |
| 48 | transition:border-color .2s; |
| 49 | box-sizing:border-box |
| 50 | } |
| 51 | .input:focus { |
| 52 | border-color:#00FF41; |
| 53 | box-shadow:0 0 0 3px rgba(0, |
| 54 | 255, |
| 55 | 65, |
| 56 | .1) |
| 57 | } |
| 58 | .input::placeholder { |
| 59 | color:#525252 |
| 60 | } |
| 61 | .pw-wrap { |
| 62 | position:relative |
| 63 | } |
| 64 | .pw-toggle { |
| 65 | position:absolute; |
| 66 | right:8px; |
| 67 | top:50%; |
| 68 | transform:translateY(-50%); |
| 69 | background:none; |
| 70 | border:none; |
| 71 | color:#525252; |
| 72 | cursor:pointer; |
| 73 | padding:4px; |
| 74 | display:flex; |
| 75 | transition:color .2s; |
| 76 | line-height:1 |
| 77 | } |
| 78 | .pw-toggle:hover { |
| 79 | color:#00FF41 |
| 80 | } |
| 81 | .btn { |
| 82 | width:100%; |
| 83 | padding:10px; |
| 84 | border-radius:8px; |
| 85 | font-size:13px; |
| 86 | font-weight:600; |
| 87 | font-family:inherit; |
| 88 | cursor:pointer; |
| 89 | background:#00FF41; |
| 90 | color:#0A0A0A; |
| 91 | border:none; |
| 92 | transition:all .2s; |
| 93 | margin-top:8px |
| 94 | } |
| 95 | .btn:hover { |
| 96 | background:#00E63A |
| 97 | } |
| 98 | .divider { |
| 99 | border:none; |
| 100 | border-top:1px solid #222; |
| 101 | margin:20px 0 |
| 102 | } |
| 103 | .terms { |
| 104 | font-size:11px; |
| 105 | color:#525252; |
| 106 | text-align:center; |
| 107 | margin-top:16px |
| 108 | } |
| 109 | .terms a { |
| 110 | color:#808080 |
| 111 | } |
untitled.js
JavaScript
| 1 | document.querySelectorAll('.pw-toggle').forEach(btn=>{btn.addEventListener('click',()=>{const inp=document.getElementById(btn.dataset.for);const isPw=inp.type==='password';inp.type=isPw?'text':'password';btn.querySelector('svg').innerHTML=isPw?'<path d="M17.94 17.94A10.07 10.07 0 0 1 12 20c-7 0-11-8-11-8a18.45 18.45 0 0 1 5.06-5.94M9.9 4.24A9.12 9.12 0 0 1 12 4c7 0 11 8 11 8a18.5 18.5 0 0 1-2.16 3.19m-6.72-1.07a3 3 0 1 1-4.24-4.24"/><line x1="1" y1="1" x2="23" y2="23"/>':'<path d="M1 12s4-8 11-8 11 8 11 8-4 8-11 8-11-8-11-8z"/><circle cx="12" cy="12" r="3"/>'})}) |