<div class="wf-form">
<div class="wf-field">
<label for="name">Full name</label>
<input class="wf-input" type="text" id="name" placeholder="Alice Johnson">
<span class="wf-field-hint">Enter your legal full name.</span>
</div>
<div class="wf-field">
<label for="email">Email address</label>
<input class="wf-input" type="email" id="email" placeholder="alice@example.com">
</div>
</div>
<!-- Hint with icon -->
<span class="wf-field-hint"><i class="icon notification"></i> Shown on your public profile.</span>
Forms
Flexible form primitives for every input scenario. Compose fields with labels, hints, icon overlays, prefix and suffix addons, action buttons, and validation states. Covers text inputs, textarea, select, checkboxes, radio buttons, and toggle switches.
Basic
Wrap your form in wf-form to control vertical field spacing. Each wf-field stacks a label , a control, and an optional wf-field-hint .
Controls
Apply wf-input , wf-textarea , or wf-select to the corresponding HTML element. All three share the same border, focus ring, disabled, and readonly styles. Add wf-input-transparent for a borderless underline variant.
Textarea wf-textarea
<div class="wf-field">
<label for="message">Message</label>
<textarea class="wf-textarea" id="message" placeholder="Type your message…"></textarea>
</div>
Select wf-select
<div class="wf-field">
<label for="country">Country</label>
<select class="wf-select" id="country">
<option value="">Choose a country…</option>
<option>Australia</option>
</select>
</div>
Transparent wf-input-transparent
Borderless input with only a bottom border. Focus draws a primary-colored underline.
<input class="wf-input wf-input-transparent" type="text" placeholder="Search…">
Multi-field Rows
Wrap multiple wf-field elements in wf-fields to arrange them side by side. All fields share equal width by default. Add a proportional modifier — wf-field-2 through wf-field-7 — to control the flex ratio of individual fields. The row collapses to a single column on small screens.
<!-- Equal-width fields -->
<div class="wf-fields">
<div class="wf-field">…</div>
<div class="wf-field">…</div>
<div class="wf-field">…</div>
</div>
<!-- Proportional: 30% / 70% -->
<div class="wf-fields">
<div class="wf-field wf-field-3">…</div>
<div class="wf-field wf-field-7">…</div>
</div>
Icon Overlays
Wrap the input in wf-input-wrap and add wf-has-icon-left or wf-has-icon-right . Use wf-input-icon for a decorative icon or wf-input-icon-btn for a clickable one.
Icon left
<div class="wf-input-wrap wf-has-icon-left">
<span class="wf-input-icon"><i class="icon user"></i></span>
<input class="wf-input" type="text" id="icon-user" placeholder="alice">
</div>
Clickable icon right
<!-- wf-input-icon-btn is clickable -->
<div class="wf-input-wrap wf-has-icon-right">
<input class="wf-input" type="password" placeholder="••••••••">
<button class="wf-input-icon-btn" type="button">
<i class="icon locked circle"></i>
</button>
</div>
Addons & Actions
Add wf-input-addon inside wf-input-wrap with prefix or suffix for text addons. Use wf-input-addon or to attach a wf-btn flush with the input edge.
Prefix
<div class="wf-input-wrap">
<span class="wf-input-addon">https://</span>
<input class="wf-input" type="text" placeholder="example.com">
</div>
Suffix
<div class="wf-input-wrap">
<input class="wf-input" type="text" placeholder="alice">
<span class="wf-input-addon">@example.com</span>
</div>
Prefix and Suffix
<div class="wf-input-wrap">
<span class="wf-input-addon wf-input-addon-plain">$</span>
<input class="wf-input" type="text" placeholder="0.00m">
<span class="wf-input-addon wf-input-addon-outlined">USD</span>
</div>
Action right
<div class="wf-input-wrap">
<input class="wf-input" type="text" placeholder="Search…">
<button class="wf-btn wf-btn-primary" type="button">Go</button>
</div>
Action left
<div class="wf-input-wrap">
<button class="wf-btn" type="button">+1</button>
<input class="wf-input" type="tel" placeholder="555-0100">
</div>
Checkboxes, Radios & Toggles
Each control wraps a visually hidden input and a styled label . Group them vertically with wf-check-group or horizontally with wf-check-group-inline .
Checkboxes
<div class="wf-check-group">
<div class="wf-checkbox">
<input type="checkbox" id="opt1" checked>
<label for="opt1">Email notifications</label>
</div>
<div class="wf-checkbox">
<input type="checkbox" id="opt2">
<label for="opt2">Product updates</label>
</div>
</div>
Radio buttons
<div class="wf-check-group">
<div class="wf-radio">
<input type="radio" name="plan" id="free" checked>
<label for="free">Free</label>
</div>
<div class="wf-radio">
<input type="radio" name="plan" id="pro">
<label for="pro">Pro</label>
</div>
</div>
Toggles
<!-- Inline group -->
<div class="wf-check-group-inline">
<div class="wf-toggle">
<input type="checkbox" id="dark" checked>
<label for="dark">Dark mode</label>
</div>
<div class="wf-toggle">
<input type="checkbox" id="notif">
<label for="notif">Notifications</label>
</div>
</div>
Sliders
Pill Sliders
<!-- Slider Inline group -->
<div class="wf-toggle-slide">
<input type="radio" id="soft-1" name="soft" checked="">
<label for="soft-1">Starter</label>
<input type="radio" id="soft-2" name="soft">
<label for="soft-2">Business</label>
<!-- ... -->
</div>
<!-- Pill Variant -->
<div class="wf-toggle-slide wf-toggle-slide-pill">
<!-- ... -->
</div>
Sizes
Add wf-field-sm or wf-field-lg to the field wrapper to scale all controls inside. For a standalone input inside an wf-input-wrap , use wf-input-sm or wf-input-lg on the wrap itself.
Small wf-field-sm
<div class="wf-field wf-field-sm">
<label>Full name</label>
<input class="wf-input" type="text" placeholder="Alice Johnson">
</div>
Large wf-field-lg
<div class="wf-field wf-field-lg">
<label>Full name</label>
<input class="wf-input" type="text" placeholder="Alice Johnson">
</div>
States
Add a validation state class to the wf-field wrapper to tint the control border and background. Use wf-required on the label (or wf-field-required on the wrapper) to show a red asterisk. Apply wf-field-disabled to the wrapper to lock the entire field.
Error
<div class="wf-field wf-field-error">
<label for="email">Email address</label>
<input class="wf-input" type="email" id="email" value="not-an-email">
<span class="wf-field-hint">Please enter a valid email address.</span>
</div>
Warning
<div class="wf-field wf-field-warning">
<label>Username</label>
<input class="wf-input" type="text" value="alice_j">
<span class="wf-field-hint">This username is already taken.</span>
</div>
Success
<div class="wf-field wf-field-success">
<label>Username</label>
<input class="wf-input" type="text" value="alice_johnson">
<span class="wf-field-hint">Username is available.</span>
</div>
Info
<div class="wf-field wf-field-info">
<label>API key</label>
<input class="wf-input" type="text" value="sk-••••••••••" readonly>
<span class="wf-field-hint">Your key is read-only.</span>
</div>
Required
<!-- Required asterisk on label -->
<div class="wf-field">
<label class="wf-required">Email address</label>
<input class="wf-input" type="email" placeholder="alice@example.com">
</div>
<!-- Or on the field wrapper -->
<div class="wf-field wf-field-required">
<label>Email address</label>
<input class="wf-input" type="email">
</div>
Disabled
<div class="wf-field wf-field-disabled">
<label>Account ID</label>
<input class="wf-input" type="text" value="USR-00142" readonly>
<span class="wf-field-hint">Cannot be changed.</span>
</div>
Inline Layout
Replace wf-field with wf-field-inline to use a two-column grid where the label sits in a fixed-width column on the left and the control expands to fill the rest. Collapses to stack on small screens.
<div class="wf-form">
<div class="wf-field-inline">
<label class="wf-required">Full name</label>
<input class="wf-input" type="text" id="name" placeholder="Alice Johnson">
<label class="wf-required">Email</label>
<input class="wf-input" type="email" id="email" placeholder="alice@example.com">
</div>
</div>
Custom Properties
| Property | Default | Description |
|---|---|---|
| --wf-gap | var(--wf-space-5) | Vertical gap between fields in wf-form and horizontal gap in wf-fields . |
| --wf-surface | #fff | Background color for all controls. |
| --wf-surface-subtle | #f7f8fa | Background for disabled and readonly controls. |
| --wf-border | #e5e7eb | Default border color for all controls. |
| --wf-text | #252f4a | Control value text color and label color. |
| --wf-text-muted | #6b7280 | Placeholder text, addon text, and hint color. |
| --wf-radius-control | var(--wf-radius-4) | Border radius is applied to inputs, select, and addons. |
| --wf-field-label-width | 9rem | Override the label column width in inline fields. |
Class Reference
All modifier classes available on .wf-form
| Class | Type | Description |
|---|---|---|
| wf-form | Base | Flex column container for a complete form. Controls the vertical gap between fields via --wf-gap . |
| wf-field | Layout | Individual field wrapper — stacks label, control, and hint vertically. |
| wf-field-hint | Part | Helper text is displayed below the control. Supports an optional leading icon. |
| wf-fields | Layout | Flex-wrap row for placing multiple fields side by side. Collapses to full-width on small screens. |
| wf-field-2 / wf-field-3 / wf-field-4 / wf-field-5 / wf-field-6 / wf-field-7 | Modifier | Proportional width inside wf-fields : 20%, 30%, 40%, 50%, 60%, 70%. |
| wf-input | Base | Styled text input. Apply to any input element. |
| wf-textarea | Base | Styled textarea with vertical resize and a 6.5rem minimum height. |
| wf-select | Base | Styled select with a custom dropdown arrow. |
| wf-input-transparent | Modifier | Removes a box border; shows only a bottom border. Focuses with a primary-colored underline. |
| wf-input-wrap | Layout | Stretch-aligned flex row for composing inputs with icons, addons, and action buttons. |
| wf-input-icon | Part | Non-interactive icon overlay inside wf-input-wrap . |
| wf-input-icon-btn | Part | Clickable icon button overlay; same position as wf-input-icon . |
| wf-input-addon | Part | Prefix or suffix the text badge attached to the input border. |
| wf-has-icon-left / wf-has-icon-right | Modifier | On wf-input-wrap : positions the icon and adds the matching inner padding to the input. |
| wf-has-prefix / wf-has-suffix | Modifier | On wf-input-wrap : attaches the addon and adjusts input border-radius accordingly. |
| wf-has-action / wf-has-action-left | Modifier | On wf-input-wrap : appends or prepends a wf-btn flush with the input. |
| wf-radio | Base | Single radio button — wraps a hidden input[type=radio] and its label . |
| wf-checkbox | Base | Single checkbox — wraps a hidden input[type=checkbox] and its label . |
| wf-toggle | Base | Toggle switch — same structure as wf-checkbox with a pill-shaped track. |
| wf-check-group | Layout | Vertical stack for a list of checkboxes, radios, or toggles. |
| wf-check-group-inline | Layout | Horizontal flex-wrap row for inline checkboxes, radios, or toggles. |
| wf-radio-sm / wf-checkbox-sm / wf-toggle-sm | Modifier | Reduces the indicator size for compact layouts. |
| wf-required | Modifier | On a label : appends a red asterisk. Also supported as wf-field-required on the wf-field wrapper. |
| wf-field-disabled | State | Disables pointer events and reduces opacity on the entire field. |
| wf-field-error / wf-field-warning / wf-field-success / wf-field-info | State | Validation states on the wf-field wrapper — tints the control border and background with the matching semantic color. |
| wf-field-sm / wf-field-lg | Modifier | Small (0.875rem) or large (1.125rem) font size and padding for all controls inside the field. |
| wf-input-wrap.wf-input-sm / wf-input-wrap.wf-input-lg | Modifier | Size modifier for an wf-input-wrap and all its children (input, addon, icon). |
| wf-field-inline | Layout | Two-column grid layout: fixed-width label on the left, full-width control on the right. Collapses to stack on small screens. |