Skip to content

Form

All form elements are fully responsive with pure semantic HTML, enabling forms to scale gracefully across devices and viewports.

scss
@use '@natachah/vanilla-frontend/scss/components/form'

Syntax

The form is using the native <label>, <input> and co. tags.

html
<label for="demoInput">Input</label>
<input type="text" id="demoInput" name="input" placeholder="My input" aria-describedby="demoInputDescription">
<small id="demoInputDescription">
    Must be at least 8 characters.
</small>
css
--form-color
--form-background
--form-border-size
--form-border-style
--form-border-color
--form-border-radius
--form-padding-inline
--form-padding-block
--form-transition
--form-decoration

Inputs

html
<input type="text" name="text" placeholder="Some text">
<input type="search" name="search" placeholder="Enter some keyword">
<input type="email" name="email" placeholder="info@something.com">
<input type="url" name="url" placeholder="http://www.google.com">
<input type="tel" name="tel" placeholder="021 922 00 00">
<input type="number" name="number" placeholder="42">
<input type="password" name="password" placeholder="123456">

The type file come with a default icon and no button.

html
<input type="file" name="file" accept="image/png, image/jpeg">
css
--icon-file

The type date, time and datetime-local come with default icon.

html
<input type="date" name="date">
<input type="time" name="time">
<input type="datetime-local" name="datetime">
css
--icon-date
--icon-time

The type color is also consistent with the other input types.

html
<input type="color" name="color">

The range field look more like a progress bar.

html
<input type="range" name="range" min="0" max="10">

Textarea

The native <textarea> is styled like the input for consistency.

By default you only can resize the height.

html
<textarea name="textarea" rows="5" cols="33">It was a dark and stormy night...</textarea>

Select

The native <select> is styled like the input for consistency.

html
<select name="select">
    <option value="1">One</option>
    <option value="2">Two</option>
    <option value="3">Three</option>
    <option value="4">Four</option>
</select>
css
--icon-select

Radio

The radio field must be inside a <fieldset>.

html
<fieldset>
    <legend>Radio</legend>
    <input type="radio" id="radioA" name="radio" checked> <label for="radioA">Option A</label>
    <input type="radio" id="radioB" name="radio"> <label for="radioB">Option B</label>
    <input type="radio" id="radioC" name="radio"> <label for="radioC">Option C</label>
</fieldset>
css
--icon-radio
--form-active-background
--form-active-border-color

To display the element into the vertical, surround the <input> and the <label> by a <div> tag.

html
<fieldset>
    <legend>Radio</legend>
    <div>
        <input type="radio" id="radioD" name="radio" checked> <label for="radioD">Option D</label>
    </div>
    <div>
        <input type="radio" id="radioE" name="radio"> <label for="radioE">Option E</label>
    </div>
    <div>
        <input type="radio" id="radioF" name="radio"> <label for="radioF">Option F</label>
    </div>
</fieldset>

Checkbox

The checkbox field must be inside a <fieldset>.

html
<fieldset>
    <legend>Checkbox</legend>
    <input type="checkbox" id="checkboxA" name="checkboxA" checked> <label for="checkboxA">Option A</label>
    <input type="checkbox" id="checkboxB" name="checkboxB"> <label for="checkboxB">Option B</label>
    <input type="checkbox" id="checkboxC" name="checkboxC"> <label for="checkboxC">Option C</label>
</fieldset>
css
--icon-check
--form-active-background
--form-active-border-color

To display the element into the vertical, surround the <input> and the <label> by a <div> tag.

html
<fieldset>
    <legend>Radio</legend>
    <div>
        <input type="checkbox" id="checkboxD" name="checkbox" checked> <label for="checkboxD">Option D</label>
    </div>
    <div>
        <input type="checkbox" id="checkboxE" name="checkbox"> <label for="checkboxE">Option E</label>
    </div>
    <div>
        <input type="checkbox" id="checkboxF" name="checkbox"> <label for="checkboxF">Option F</label>
    </div>
</fieldset>

Switch

The checkbox with the role="switch" attribute will render a switch component.

html
<input type="checkbox" role="switch" id="switch" name="switch" value="true">
<label for="switch">I agree to the terms</label>
css
--icon-switch
--form-active-background
--form-active-border-color

States

The form can have the :focus, :disabled, :readonly and :validation states.

Focus

The form use a default focus style, but you can customize it with :

css
--form-focus-color
--form-focus-background
--form-focus-border-color

You can also customize the outline :

css
--form-outline-size
--form-outline-style
--form-outline-color
--form-outline-offset

Disabled

Apply the disabled attribute on <input>, <textarea> or <select> tags to display the disabled style.

html
<input type="text" value="My value" disabled>
<select type="text" disabled>
    <option value="--">--</option>
</select>
<textarea disabled>It was a dark and stormy night...</textarea>
<input type="checkbox" disabled> <input type="checkbox" disabled checked> <input type="radio" disabled> <input type="radio" disabled checked> <input type="checkbox" role="switch" disabled> <input type="checkbox" role="switch" disabled checked>
css
--form-disabled-opacity

Readonly

Apply the readonly attribute on <input> or <textarea> tags to display the readonly style.

html
<input type="text" value="My value" readonly>
<textarea readonly>It was a dark and stormy night...</textarea>

Validation

Use the aria-invalid attribute to display the element as in/valid and use aria-describedby attribute with a <small> tag to display the information.

As every design is different, there is not too much default style for in/valid elements. But for accessibility don't forget to add icons to show the errors.

html
<div>
    <label for="invalidInput">Invalid input</label>
    <input id="invalidInput" type="text" aria-describedby="invalidMsg" aria-invalid="true" value="My bad value">
    <small id="invalidMsg" >
        <span aria-live="assertive">
            <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" viewBox="0 0 16 16"><path d="M8 15A7 7 0 1 1 8 1a7 7 0 0 1 0 14m0 1A8 8 0 1 0 8 0a8 8 0 0 0 0 16"></path><path d="M7.002 11a1 1 0 1 1 2 0 1 1 0 0 1-2 0M7.1 4.995a.905.905 0 1 1 1.8 0l-.35 3.507a.552.552 0 0 1-1.1 0z"></path></svg>
            Incorrect value !
        </span>
    </small>
</div>
<div>
    <label for="validInput">Valid input</label>
    <input id="validInput" type="text" aria-describedby="validMsg" aria-invalid="false" value="My good value">
    <small id="validMsg">
        <span aria-live="assertive">
            <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" viewBox="0 0 16 16"><path d="M8 15A7 7 0 1 1 8 1a7 7 0 0 1 0 14m0 1A8 8 0 1 0 8 0a8 8 0 0 0 0 16"></path><path d="m10.97 4.97-.02.022-3.473 4.425-2.093-2.094a.75.75 0 0 0-1.06 1.06L6.97 11.03a.75.75 0 0 0 1.079-.02l3.992-4.99a.75.75 0 0 0-1.071-1.05"></path></svg>
            All good !
        </span>
    </small>
</div>
scss
form div {
    &:has([aria-invalid=true]) {
        [aria-live] {
            color: var(--color-error);
        }
    }

    &:has([aria-invalid=false]) {
        [aria-live] {
        color: var(--color-success);
        }
    }
}

Variants

Group

You can group some fields by putting them in a <div> with the class .group.

html
<fieldset>
    <legend>Price</legend>
    <div class="group">
        <label>Before</label>
        <select>
            <option value="A">CHF</option>
            <option value="B">€</option>
            <option value="C">$</option>
        </select>
        <input type="number" value="110">
        <label>After</label>
        <button>Send</button>
    </div>
</fieldset>
scss
@use '@natachah/vanilla-frontend/scss/components/group';

Released under the MIT License.