Forms¶
Structure¶
Wrap forms in .form for consistent styling. Use semantic elements:
<form class="form">
<label>
Label text
<input type="text" placeholder="Placeholder" />
</label>
<footer>
<button class="primary">Save</button>
<button type="button">Cancel</button>
</footer>
</form>
Inputs¶
Text¶
<label>
Label text
<input type="text" placeholder="Placeholder text" />
</label>
Select¶
<label>
Choose an option
<select>
<option>Option one</option>
<option>Option two</option>
</select>
</label>
Textarea¶
<label>
Description
<textarea rows="3" placeholder="Enter details..."></textarea>
</label>
Range¶
Slider for a bounded numeric value.
<input type="range" min="0" max="100" value="60" />
slider.style.setProperty('--fill', `${percent}%`); // for WebKit support
Toggle¶
On/off toggle using role="switch" on a checkbox.
<label>
<input type="checkbox" role="switch" />
Enable notifications
</label>
Help text¶
Use <small> below inputs for additional guidance.
<label>
API key
<input type="password" placeholder="sk-..." aria-describedby="api-key-hint" />
<small id="api-key-hint">Found in your provider's dashboard.</small>
</label>
Input groups¶
Button add-on¶
<div class="input-group">
<input type="text" name="name" value="llama3.2:3b" />
<button type="button">Download</button>
</div>
Status add-on¶
Use data-status="ok" for a green indicator dot.
<div class="input-group">
<input type="text" name="name" value="llama3.2:3b" />
<span data-status="ok" aria-label="Downloaded"></span>
</div>
Accessibility
Status add-ons without visible text must have aria-label.
Sections¶
Group related fields with <fieldset> and <legend>:
<fieldset>
<legend>Connection settings</legend>
<label>
Host
<input type="text" placeholder="localhost" />
</label>
<label>
Port
<input type="number" placeholder="5432" />
</label>
</fieldset>
Layout¶
Use .row for inline field groups. Children get equal width by default.
<div class="row">
<label>
First name
<input type="text" />
</label>
<label>
Last name
<input type="text" />
</label>
</div>
Sizing modifiers¶
| Class | Purpose |
|---|---|
.narrow |
Fixed 140px width |
.shrink |
Natural width, no flex |
<div class="row">
<label>
Host
<input type="text" />
</label>
<label class="narrow">
Port
<input type="number" />
</label>
</div>
Actions¶
Use <footer> for the button row at the end of a form:
<form class="form">
<!-- fields -->
<footer>
<button class="primary">Save</button>
<button type="button">Cancel</button>
</footer>
</form>
Inline errors¶
Use .alert.error after the form actions for validation feedback:
Passphrases do not match.
<form class="form">
<!-- fields -->
<footer>
<button class="primary">Submit</button>
</footer>
<div class="alert error" role="alert">Passphrases do not match.</div>
</form>