1. Basic Form — clean labels, rounded inputs, primary button
<form> <label>Name</label> <input type="text" placeholder="Ada Lovelace"> <label>Email</label> <input type="email"> <label>Message</label> <textarea rows="4"></textarea> <button type="submit">Submit</button> </form>
form { display: flex; flex-direction: column; gap: 14px; } input, textarea, select { padding: 12px 14px; border: 1px solid #d4d4d8; border-radius: 8px; } input:focus { outline: none; border-color: #111; }
2. Floating Label — label shrinks up on focus (peer selector trick)
<div class="field"> <!-- placeholder=" " is critical for :placeholder-shown --> <input type="text" id="fname" placeholder=" "> <label for="fname">Full Name</label> </div>
.field { position: relative; } .field input { padding: 22px 14px 10px; /* room for label inside */ } .field label { position: absolute; top: 14px; left: 14px; color: #888; pointer-events: none; transition: all .2s; } /* Shrink label when input is focused OR has content */ input:focus + label, input:not(:placeholder-shown) + label { top: 5px; font-size: 11px; color: #ec4899; }
3. Custom Radio & Checkbox — fully styled, keyboard-accessible
Pick one — Subscription plan
Select interests
<label class="opt"> <!-- Real input is hidden; .box is the visual --> <input type="checkbox"> <span class="box"></span> Design </label>
/* Hide the real input */ input[type="checkbox"], input[type="radio"] { display: none; } .box { width: 20px; height: 20px; border: 2px solid #d4d4d8; border-radius: 6px; display: flex; align-items: center; justify-content: center; } /* Inner dot drawn with ::after, scaled to 0 by default */ .box::after { content: ""; width: 10px; height: 10px; background: #fff; border-radius: 3px; transform: scale(0); transition: transform .15s; } /* Adjacent sibling combinator: when input is checked, style .box */ input:checked + .box { background: #ec4899; border-color: #ec4899; } input:checked + .box::after { transform: scale(1); }
4. Validation States — success, error, and helper messages
<div class="field success"> <label>Username</label> <input type="text"> <i class="ph-fill ph-check-circle state-icon"></i> <div class="msg">Username is available</div> </div> <div class="field error"> <!-- same structure, different class --> </div>
.field.success input { border-color: #10b981; } .field.success .msg { color: #10b981; } .field.success .state-icon { color: #10b981; } .field.error input { border-color: #ef4444; background: #fef2f2; } .field.error .msg { color: #ef4444; } /* Icon sits inside the input on the right */ .state-icon { position: absolute; right: 12px; top: 50%; transform: translateY(-50%); }
5. Range Slider + Toggle Switch — styled with custom thumb + sliding pill
<input type="range" min="0" max="10000" value="2500"> <span class="switch"> <input type="checkbox" checked> <span class="switch-slider"></span> </span>
/* Style the range thumb (WebKit) */ input[type="range"]::-webkit-slider-thumb { -webkit-appearance: none; width: 22px; height: 22px; border-radius: 50%; background: linear-gradient(135deg, #ec4899, #8b5cf6); cursor: pointer; } /* Toggle switch — checkbox hack */ .switch { width: 46px; height: 26px; position: relative; } .switch input { display: none; } .switch-slider { position: absolute; inset: 0; background: #d4d4d8; border-radius: 999px; } .switch-slider::before { content: ""; position: absolute; width: 20px; height: 20px; left: 3px; top: 3px; background: #fff; border-radius: 50%; transition: transform .2s; } /* When checked, slide the knob + color the track */ input:checked + .switch-slider { background: #10b981; } input:checked + .switch-slider::before { transform: translateX(20px); }
6. Multi-Step Form — progress indicator + step-by-step fields
Step 3 of 4
About You
<div class="steps"> <div class="step done"></div> <div class="step done"></div> <div class="step current"></div> <div class="step"></div> </div> <form><!-- fields for current step --></form>
.steps { display: flex; gap: 8px; } .step { flex: 1; height: 6px; background: #e5e7eb; border-radius: 999px; } .step.done { background: #ec4899; } /* Half-filled for current step */ .step.current { background: linear-gradient(90deg, #ec4899 50%, #e5e7eb 50%); }
7. Search with Suggestions — icon inside input + dropdown list
- Cards LabLab
- Icon TutorialTutorial
- Neumorphism LabLab
- SVG LabLab
<div class="search"> <i class="ph ph-magnifying-glass"></i> <input type="search" placeholder="Search..."> </div> <ul class="suggestions"> <li>Cards Lab</li> <li>Icon Tutorial</li> </ul>
.search { position: relative; } /* Push input text to the right of the icon */ .search input { padding-left: 44px; border-radius: 999px; background: #f4f4f5; border-color: transparent; } .search i { position: absolute; left: 16px; top: 50%; transform: translateY(-50%); color: #888; } .suggestions li { padding: 10px 16px; display: flex; gap: 10px; cursor: pointer; } .suggestions li:hover { background: #f9f9fa; }
8. File Upload — drag-and-drop zone with file preview list
sunset-draft.jpg 2.4 MB
brand-guide.pdf 8.1 MB
<!-- <label> wraps the input so whole area is clickable --> <label class="drop"> <div class="icon"><i class="ph-duotone ph-cloud-arrow-up"></i></div> <h4>Drop files here or click to browse</h4> <p>PNG, JPG, PDF up to 10MB</p> <input type="file" multiple> </label>
.drop { border: 2px dashed #d4d4d8; border-radius: 14px; padding: 38px 20px; text-align: center; background: #fafafa; cursor: pointer; transition: all .2s; } .drop:hover { border-color: #ec4899; background: #fdf2f8; } /* Hide the real input — the label is the UI */ .drop input { display: none; }
9. All Input Types — every HTML5 input, select, textarea, and button, each with a label
<!-- All HTML5 input types pair with a <label for=""> --> <label for="name">Name</label> <input id="name" type="text"> <!-- Numbers & range --> <input type="number" min="0" max="100"> <input type="range" min="0" max="100" value="50"> <!-- Date/time family --> <input type="date"> <input type="time"> <input type="datetime-local"> <input type="month"> <input type="week"> <!-- Pickers --> <input type="color" value="#ec4899"> <input type="file"> <!-- Autocomplete with datalist --> <input list="frameworks"> <datalist id="frameworks"> <option value="Astro"> <option value="Next.js"> </datalist> <!-- Choices --> <select><option>Single</option></select> <select multiple><option>Multi</option></select> <input type="radio" name="plan"> <input type="checkbox"> <!-- Buttons --> <button type="submit">Submit</button> <button type="reset">Reset</button> <button type="button">Plain</button> <!-- Group related inputs with fieldset + legend --> <fieldset> <legend>Contact info</legend> <!-- fields here --> </fieldset>
/* Fieldset = visual group for related fields */ fieldset { border: 1px solid #e5e7eb; border-radius: 12px; padding: 16px 18px; } /* Legend sits on the border — nice accent */ legend { font-size: 11px; font-weight: 700; letter-spacing: .1em; text-transform: uppercase; color: #ec4899; padding: 0 6px; } /* Range slider needs some special handling */ input[type="range"] { padding: 0; border: none; background: transparent; } /* Color input needs smaller padding */ input[type="color"] { padding: 2px; height: 36px; } /* <output> displays computed form values */ output { font-weight: 700; color: #ec4899; font-variant-numeric: tabular-nums; }