Spruce CSS comes with overall form support for styling the different native elements. Also, it has some form layout helpers.

We differentiate the following groups for styling:

  • the form-control class is used for input (not radio, checkbox, range, or file), textarea, select elements,
  • the form-check is used for radio and checkbox,
  • the form-switch is used for switch-styled checkboxes,
  • the form-range is used for range typed input,
  • the form-file is used for file typed input.

Input

Use the form-control class on the input (that doesn’t have the type of radio, checkbox, or range) and form-label on the label elements to apply the formatting.

Wrap the label and the input into form-group elements to control the two’s margin.

You can set two additional sizes with form-control--sm and form-control--lg modifier class.

Form-control related variables.

html
<div class="form-group">
<label class="form-label" for="your-name">Name</label>
<input class="form-control" id="your-name" name="your-name" type="text"/>
</div>
<div class="form-group">
<label class="form-label" for="your-email">Email</label>
<input class="form-control" id="your-email" name="your-email" type="email"/>
</div>
<div class="form-group">
<label class="form-label" for="your-birthday">Birthday</label>
<input class="form-control" id="your-birthday" name="your-birthday" type="date"/>
</div>
<div class="form-group">
<label class="form-label" for="your-color">Your favorite color</label>
<input class="form-control" id="your-color" name="your-color" type="color" value="#6524d6"/>
</div>

File

Use the form-file class on an input[type="file"] to nativly stlye the file input.

  • You can size the input with form-file--sm and form-file--lg.
  • The styling is the same as the .btn.
  • The focus state differs from the button because we can’t set box-shadow (it will be cut down).

Form-file related variables.

File Inputs
html
<fieldset>
<legend>File Inputs</legend>
<div class="form-group">
<label class="form-label" for="avatar-lg">Avatar (Large)</label>
<input class="form-file form-file--lg" type="file" id="avatar-lg" accept="image/png, image/jpeg"/>
</div>
<div class="form-group">
<label class="form-label" for="avatar">Avatar</label>
<input class="form-file form-file" type="file" id="avatar" accept="image/png, image/jpeg"/>
</div>
<div class="form-group">
<label class="form-label" for="files">Files</label>
<input class="form-file form-file--sm" type="file" id="files" multiple="multiple" accept="image/png, image/jpeg"/>
</div>
</fieldset>

Range

Use the form-range class on an input[type="range"] to natively style the range input.

  • You can size the input with form-range--sm and form-range--lg.

Form-range related variables.

Range
html
<fieldset>
<legend>Range</legend>
<div class="form-group">
<label class="form-label" for="rating">Your Rating</label>
<input class="form-range form-range--lg" type="range" id="rating" min="-10" max="10"/>
</div>
</fieldset>

Textarea

Use the form-control class on any textarea element to style it. To set the global height of it use the $form-control-textarea-height variable.

html
<div class="form-group">
<label class="form-label" for="your-message">Your Message</label>
<textarea class="form-control" id="your-message" name="your-message" placeholder="Write your message..." rows="4"></textarea>
</div>

Select

Use the form-control class on any select element to style it. Use the multiple attributes for multiple option selection.

Select related variables.

html
<div class="form-group">
<label class="form-label" for="front-end-frameworks">Front-end Frameworks</label>
<select class="form-control" id="front-end-frameworks">
<option value="react">React</option>
<option value="vue">Vue</option>
<option value="svelte">Svelte</option>
<option value="ember">Ember</option>
</select>
</div>
<div class="form-group">
<label class="form-label" for="front-end-frameworks-multiple">Front-end Frameworks (Mulitple)</label>
<select class="form-control" id="front-end-frameworks-multiple" multiple="multiple">
<option value="react">React</option>
<option value="vue">Vue</option>
<option value="svelte">Svelte</option>
<option value="ember">Ember</option>
</select>
</div>

Radio

For styling radio elements, use the form-check class on the label element and place the input (with the form-check__control class) and span (with the form-check__label class) inside it.

  • Use the form-group--vertical-check modifier class to align the group vertically,
  • and the form-group--horizontal-check to align horizontally.

You can set two additional sizes with form-check--sm and form-check--lg modifier class.

Check related variables.

Radio (Vertical)
html
<fieldset>
<legend>Radio (Vertical)</legend>
<div class="form-group form-group--vertical-check">
<label class="form-check">
<input class="form-check__control" type="radio" value="react" name="radio-example-vertical"/>
<span class="form-label form-check__label">React</span>
</label>
<label class="form-check">
<input class="form-check__control" type="radio" value="vue" name="radio-example-vertical" disabled="disabled"/>
<span class="form-label form-check__label">Vue</span>
</label>
<label class="form-check">
<input class="form-check__control" type="radio" value="svelte" name="radio-example-vertical"/>
<span class="form-label form-check__label">Svelte</span>
</label>
<label class="form-check">
<input class="form-check__control" type="radio" value="ember" name="radio-example-vertical"/>
<span class="form-label form-check__label">Ember</span>
</label>
</div>
</fieldset>
Radio (Horizontal)
html
<fieldset>
<legend>Radio (Horizontal)</legend>
<div class="form-group form-group--horizontal-check">
<label class="form-check">
<input class="form-check__control" type="radio" value="react" name="radio-example-horizontal"/>
<span class="form-label form-check__label">React</span>
</label>
<label class="form-check">
<input class="form-check__control" type="radio" value="vue" name="radio-example-horizontal"/>
<span class="form-label form-check__label">Vue</span>
</label>
<label class="form-check">
<input class="form-check__control" type="radio" value="svelte" name="radio-example-horizontal"/>
<span class="form-label form-check__label">Svelte</span>
</label>
<label class="form-check">
<input class="form-check__control" type="radio" value="ember" name="radio-example-horizontal"/>
<span class="form-label form-check__label">Ember</span>
</label>
</div>
</fieldset>

Checkbox

Use the form-check class on the label element for styling checkbox elements and place the input (with the form-check__control class) and span (with the form-check__label class) inside it. You can also display an indeterminate state programmatically.

Checkbox
html
<fieldset>
<legend>Which one of you like?</legend>
<div class="form-group form-group--vertical-check">
<label class="form-check">
<input class="form-check__control" type="checkbox" value="own" name="property-ownership2"/>
<span class="form-label form-check__label">Own</span>
</label>
<label class="form-check">
<input class="form-check__control" type="checkbox" value="rent" name="property-ownership2" disabled="disabled"/>
<span class="form-label form-check__label">Rent</span>
</label>
<label class="form-check">
<input class="form-check__control" type="checkbox" value="misc" name="property-ownership2"/>
<span class="form-label form-check__label">Misc</span>
</label>
<label class="form-check">
<input class="form-check__control" id="indeterminate" type="checkbox" value="misc" name="property-ownership2"/>
<span class="form-label form-check__label">Indeterminate</span>
</label>
</div>
</fieldset>

Switch

The switch is a styled checkbox. Use the form-switch class to display it.

You can set two additional sizes with form-switch--sm and form-switch--lg modifier class.

Switch related variables.

html
<div class="form-group form-group--vertical-check">
<label class="form-switch form-switch--sm">
<span class="form-label form-switch__label">Enable notifications</span>
<input class="form-switch__control" type="checkbox" value="true"/>
</label>
<label class="form-switch">
<input class="form-switch__control" type="checkbox" value="true"/>
<span class="form-label form-switch__label">Enable notifications</span>
</label>
<label class="form-switch form-switch--lg form-switch--block">
<span class="form-label form-switch__label">Enable notifications</span>
<input class="form-switch__control" type="checkbox" value="true"/>
</label>
<label class="form-switch form-switch--lg form-switch--block">
<input class="form-switch__control" type="checkbox" value="true" disabled="disabled"/>
<span class="form-label form-switch__label">Enable notifications</span>
</label>
</div>

Fieldset

You can use fieldset and legend elements to group more fields and set a vertical margin between them.

Your Name
html
<fieldset>
<legend>Your Name</legend>
<div class="form-group">
<label class="form-label" for="first-name">First Name</label>
<input class="form-control" id="first-name" name="first-name" type="text"/>
</div>
<div class="form-group">
<label class="form-label" for="last-name">Last Name</label>
<input class="form-control" id="last-name" name="last-name" type="text"/>
</div>
</fieldset>

Description

Use the form-description class to create a description text under an input element.

Just a help text for presentation purposes.

Validation

You can set valid and invalid states on form-control elements using the form-control--valid and form-control--invalid class modifiers.

Also, you can display separate messages using the field-feedback class and its modifiers.

Address
Looks fine
Not that fine

Disabled

Using the disabled attribute, you can create disabled state on inputs.

Form Group

Form-group is the generic container class for form elements. Besides the basic implementations, you can use the followings:

  • form-group--vertical-check: to stack the radio, checkbox, and switches vertically.
  • form-group--horizontal-check: to stack the radio, checkbox, and switches horizontally.
  • form-group--row: to align the label to the left side of the group.
  • form-group--stacked: to stack the inputs beside each other.
Form Group Row
Just a help text for presentation purpose
html
<fieldset>
<legend>Form Group Row</legend>
<div class="form-group--row">
<label class="form-label" for="first-name-row">First Name</label>
<input class="form-control" id="first-name-row" type="text"/>
<span class="form-description">Just a help text for presentation purpose</span>
</div>
<div class="form-group--row">
<label class="form-label" for="front-end-frameworks-row">Front-end Frameworks</label>
<select class="form-control" id="front-end-frameworks-row">
<option value="react">React</option>
<option value="vue">Vue</option>
<option value="svelte">Svelte</option>
<option value="ember">Ember</option>
</select>
</div>
</fieldset>
Form Group Stacked
html
<fieldset>
<legend>Form Group Stacked</legend>
<div class="form-group--stacked">
<input class="form-control" type="text" aria-label="First Name"/>
<input class="form-control" type="text" aria-label="Last Name"/>
</div>
<div class="form-group--stacked">
<input class="form-control" type="text" aria-label="First Name"/>
<input class="form-control" type="text" aria-label="Last Name"/>
<button class="btn btn--primary">Submit</button>
</div>
</fieldset>

Row

You can create a row stack using form-row--mixed class. It uses flexbox and automatically sets the columns based on the --col-width custom property.

html
<div class="form-row--mixed">
<div class="form-group" style="--col-width: 30ch">
<label class="form-label" for="city">City</label>
<input class="form-control" id="city" name="city" type="text"/>
</div>
<div class="form-group">
<label class="form-label" for="state">State</label>
<input class="form-control" id="state" name="state" type="text"/>
</div>
<div class="form-group">
<label class="form-label" for="zip">Zip</label>
<input class="form-control" id="zip" name="zip" type="text"/>
</div>
</div>