Forms

v1.0.0

Native controls with consistent labels, spacing, validation and actions.

Overview

Forms style native inputs, selects, choices, range sliders and switches. See their pages for details.

Input

Use .form-control for native input and textarea elements.

View input

Select

Use .form-select for native select elements.

View select

Checkbox

Use .form-check and .form-check-input for checkboxes.

View checkbox

Radio

Use .form-check and .form-check-input for radio groups.

View radio

Switch

Use .form-switch and .form-switch-input for toggle switches.

View switch

Range Slider

Use .range-slider-input for native range inputs with a custom track and thumb.

View range slider

Basic structure

Use .form-label with the matching control class.

<div class="mb-3">
	<label class="form-label" for="email">E-Mail</label>
	<input class="form-control" id="email" name="email" type="email" placeholder="your email" />
</div>

Required fields

Use native required and mark its label with .is-required.

<div class="mb-3">
	<label class="form-label is-required" for="fullname">Fullname</label>
	<input class="form-control" id="fullname" name="fullname" required />
</div>

Validation

Combine .is-invalid and aria-invalid=“true”. Link .invalid-feedback with aria-describedby and its id.

<div class="mb-3">
	<label class="form-label" for="invalidEmail">E-Mail</label>
	<input
		class="form-control is-invalid"
		id="invalidEmail"
		name="invalidEmail"
		type="email"
		aria-invalid="true"
		aria-describedby="invalidEmailFeedback" />
	<div class="invalid-feedback" id="invalidEmailFeedback">
		Please enter a valid email address.
	</div>
</div>

Extended form example

Notification type
8 items
<form>
	<div class="mb-3">
		<label for="salutation" class="form-label">Salutation</label>
		<select class="form-select" id="salutation" name="salutation">
			<option value="not-specified">not specified</option>
			<option value="male">Male</option>
			<option value="female">Female</option>
		</select>
	</div>

	<div class="mb-3">
		<label for="fullname" class="form-label is-required">Fullname</label>
		<input
			class="form-control"
			id="fullname"
			name="fullname"
			required
			placeholder="your fullname" />
	</div>

	<div class="mb-3">
		<label for="birthdate" class="form-label">Birthdate</label>
		<input class="form-control" id="birthdate" name="birthdate" type="date" />
	</div>

	<div class="mb-3">
		<label for="email" class="form-label is-required">E-Mail</label>
		<input
			class="form-control"
			id="email"
			name="email"
			type="email"
			pattern="[a-z0-9._%+\-]+@[a-z0-9.\-]+\.[a-z]{2,}$"
			required
			placeholder="your email" />
	</div>

	<div class="mb-3">
		<label for="message" class="form-label">Note / Message</label>
		<textarea
			class="form-control"
			id="message"
			name="message"
			placeholder="your message"></textarea>
	</div>

	<fieldset class="border border-0 min-w-0 mb-3">
		<legend class="mb-2">Notification type</legend>
		<div class="d-flex flex-column gap-2">
			<div class="form-check">
				<input
					class="form-check-input"
					id="notificationEmail"
					name="notificationType"
					type="radio"
					value="email"
					checked />
				<label class="form-label" for="notificationEmail">E-Mail</label>
			</div>

			<div class="form-check">
				<input
					class="form-check-input"
					id="notificationSms"
					name="notificationType"
					type="radio"
					value="sms" />
				<label class="form-label" for="notificationSms">SMS</label>
			</div>
		</div>
	</fieldset>

	<div class="form-switch mb-3">
		<input
			class="form-switch-input"
			id="notifications"
			name="notifications"
			type="checkbox"
			checked />
		<label class="form-label" for="notifications">Enable notifications</label>
	</div>

	<div class="range-slider mb-3">
		<div class="range-slider-header">
			<label class="form-label" for="digestLimit">Daily digest limit</label>
			<output class="range-slider-output" for="digestLimit">8 items</output>
		</div>
		<input
			class="range-slider-input"
			id="digestLimit"
			name="digestLimit"
			type="range"
			min="1"
			max="20"
			value="8"
			style="--range-slider-progress: 36.84%" />
		<div class="range-slider-marks" aria-hidden="true">
			<span>1</span>
			<span>20</span>
		</div>
	</div>

	<div class="form-check mb-3">
		<input class="form-check-input" name="privacy" id="privacy" type="checkbox" required />
		<label class="form-label is-required" for="privacy">I have read the data policy</label>
	</div>

	<div class="d-flex gap-1">
		<button id="btnCancel" type="button" class="btn btn-secondary btn-text">cancel</button>
		<button id="btnSubmit" class="btn btn-primary btn-solid" type="submit">submit</button>
	</div>
</form>

CSS Variables

Override these variables on the component or an ancestor.

--form-control-bg-color: var(--bg-surface);
--form-control-border-width: var(--border-width);
--form-control-border-color: var(--control-border-color);
--form-control-border-radius: var(--border-radius);
--form-control-padding-y: var(--spacer-1);
--form-control-padding-x: var(--spacer-3);
--form-control-font-size: var(--font-size);
--form-control-font-weight: 400;
--form-control-placeholder-color: var(--text-subtle);
--form-control-disabled-text-color: var(--disabled-text-color);
--form-control-disabled-bg-color: var(--disabled-bg-color);
--form-control-disabled-border-color: var(--disabled-border-color);
--form-control-focus-border-color: var(--primary-hover);
--form-control-focus-outline-width: var(--focus-outline-width);
--form-control-focus-outline-style: var(--focus-outline-style);
--form-control-focus-outline-color: var(--focus-outline-color);
--form-control-focus-outline-offset: var(--focus-offset);
--form-control-transition-duration: var(--transition-duration);
--form-control-transition-easing: var(--transition-easing);
--form-select-bg-color: var(--bg-surface);
--form-select-border-width: var(--border-width);
--form-select-border-color: var(--control-border-color);
--form-select-border-radius: var(--border-radius);
--form-select-padding-y: var(--spacer-1);
--form-select-padding-x: var(--spacer-3);
--form-select-indicator-padding: var(--spacer-5);
--form-select-font-size: var(--font-size);
--form-select-font-weight: 400;
--form-select-disabled-text-color: var(--disabled-text-color);
--form-select-disabled-bg-color: var(--disabled-bg-color);
--form-select-disabled-border-color: var(--disabled-border-color);
--form-select-focus-border-color: var(--primary-hover);
--form-select-focus-outline-width: var(--focus-outline-width);
--form-select-focus-outline-style: var(--focus-outline-style);
--form-select-focus-outline-color: var(--focus-outline-color);
--form-select-focus-outline-offset: var(--focus-offset);
--form-select-transition-duration: var(--transition-duration);
--form-select-transition-easing: var(--transition-easing);
--form-check-gap: var(--spacer-2);
--form-check-input-size: 1rem;
--form-check-input-border-radius: var(--border-radius-sm, 0.25rem);
--form-check-input-bg-color: var(--bg-surface);
--form-check-input-border-width: var(--border-width);
--form-check-input-border-color: var(--control-border-color);
--form-check-input-checked-bg-color: var(--primary);
--form-check-input-checked-border-color: var(--primary);
--form-check-input-checked-color: var(--on-primary);
--form-check-disabled-bg-color: var(--disabled-bg-color);
--form-check-disabled-border-color: var(--disabled-border-color);
--form-check-transition-duration: var(--transition-duration);
--form-check-transition-easing: var(--transition-easing);
--form-switch-gap: var(--spacer-2);
--form-switch-input-width: 2.5rem;
--form-switch-input-height: 1.25rem;
--form-switch-input-padding: 0.125rem;
--form-switch-input-bg-color: var(--bg-highlight);
--form-switch-input-border-width: var(--border-width);
--form-switch-input-border-color: var(--control-border-color);
--form-switch-input-border-radius: 9999px;
--form-switch-input-checked-bg-color: var(--primary);
--form-switch-input-checked-border-color: var(--primary);
--form-switch-thumb-size: 1rem;
--form-switch-thumb-bg-color: var(--bg-surface);
--form-switch-thumb-box-shadow: var(--shadow-sm);
--form-switch-thumb-checked-translate-x: calc(
	var(--form-switch-input-width) - var(--form-switch-thumb-size) -
		(var(--form-switch-input-padding) * 2) - (var(--form-switch-input-border-width) * 2)
);
--form-switch-disabled-bg-color: var(--disabled-bg-color);
--form-switch-disabled-border-color: var(--disabled-border-color);
--form-switch-disabled-thumb-bg-color: var(--disabled-text-color);
--form-switch-focus-outline-width: var(--focus-outline-width);
--form-switch-focus-outline-style: var(--focus-outline-style);
--form-switch-focus-outline-color: var(--focus-outline-color);
--form-switch-focus-outline-offset: var(--focus-offset);
--form-switch-transition-duration: var(--transition-duration);
--form-switch-transition-easing: var(--transition-easing);